aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2015-01-07 19:55:37 +0000
committerDimitry Andric <dim@FreeBSD.org>2015-01-07 19:55:37 +0000
commitca9211ecdede9bdedb812b2243a4abdb8dacd1b9 (patch)
tree9b19e801150082c33e9152275829a6ce90614b55 /test
parent8ef50bf3d1c287b5013c3168de77a462dfce3495 (diff)
downloadsrc-ca9211ecdede9bdedb812b2243a4abdb8dacd1b9.tar.gz
src-ca9211ecdede9bdedb812b2243a4abdb8dacd1b9.zip
Import compiler-rt trunk r224034.vendor/compiler-rt/compiler-rt-r224034
Notes
Notes: svn path=/vendor/compiler-rt/dist/; revision=276789 svn path=/vendor/compiler-rt/compiler-rt-r224034/; revision=276790; tag=vendor/compiler-rt/compiler-rt-r224034
Diffstat (limited to 'test')
-rw-r--r--test/BlocksRuntime/block-static.c25
-rw-r--r--test/BlocksRuntime/blockimport.c51
-rw-r--r--test/BlocksRuntime/byrefaccess.c34
-rw-r--r--test/BlocksRuntime/byrefcopy.c41
-rw-r--r--test/BlocksRuntime/byrefcopycopy.c46
-rw-r--r--test/BlocksRuntime/byrefcopyinner.c32
-rw-r--r--test/BlocksRuntime/byrefcopyint.c69
-rw-r--r--test/BlocksRuntime/byrefcopystack.c41
-rw-r--r--test/BlocksRuntime/byrefsanity.c73
-rw-r--r--test/BlocksRuntime/byrefstruct.c57
-rw-r--r--test/BlocksRuntime/c99.c20
-rw-r--r--test/BlocksRuntime/cast.c37
-rw-r--r--test/BlocksRuntime/constassign.c28
-rw-r--r--test/BlocksRuntime/copy-block-literal-rdar6439600.c29
-rw-r--r--test/BlocksRuntime/copyconstructor.C85
-rw-r--r--test/BlocksRuntime/copynull.c37
-rw-r--r--test/BlocksRuntime/dispatch_async.c57
-rw-r--r--test/BlocksRuntime/dispatch_call_Block_with_release.c31
-rw-r--r--test/BlocksRuntime/fail.c107
-rw-r--r--test/BlocksRuntime/flagsisa.c21
-rw-r--r--test/BlocksRuntime/globalexpression.c42
-rw-r--r--test/BlocksRuntime/goto.c34
-rw-r--r--test/BlocksRuntime/hasdescriptor.c29
-rw-r--r--test/BlocksRuntime/josh.C32
-rw-r--r--test/BlocksRuntime/k-and-r.c33
-rw-r--r--test/BlocksRuntime/large-struct.c51
-rw-r--r--test/BlocksRuntime/localisglobal.c42
-rw-r--r--test/BlocksRuntime/macro.c14
-rw-r--r--test/BlocksRuntime/makefile70
-rw-r--r--test/BlocksRuntime/modglobal.c18
-rw-r--r--test/BlocksRuntime/nestedimport.c44
-rw-r--r--test/BlocksRuntime/nullblockisa.c43
-rw-r--r--test/BlocksRuntime/objectRRGC.c77
-rw-r--r--test/BlocksRuntime/objectassign.c76
-rw-r--r--test/BlocksRuntime/orbars.c23
-rw-r--r--test/BlocksRuntime/rdar6396238.c32
-rw-r--r--test/BlocksRuntime/rdar6405500.c29
-rw-r--r--test/BlocksRuntime/rdar6414583.c31
-rw-r--r--test/BlocksRuntime/recursive-block.c55
-rw-r--r--test/BlocksRuntime/recursive-test.c74
-rw-r--r--test/BlocksRuntime/recursiveassign.c44
-rw-r--r--test/BlocksRuntime/reference.C95
-rw-r--r--test/BlocksRuntime/rettypepromotion.c36
-rw-r--r--test/BlocksRuntime/returnfunctionptr.c23
-rw-r--r--test/BlocksRuntime/shorthandexpression.c24
-rw-r--r--test/BlocksRuntime/sizeof.c26
-rw-r--r--test/BlocksRuntime/small-struct.c45
-rw-r--r--test/BlocksRuntime/structmember.c45
-rw-r--r--test/BlocksRuntime/testfilerunner.h110
-rw-r--r--test/BlocksRuntime/testfilerunner.m805
-rw-r--r--test/BlocksRuntime/varargs-bad-assign.c44
-rw-r--r--test/BlocksRuntime/varargs.c39
-rw-r--r--test/BlocksRuntime/variadic.c66
-rw-r--r--test/BlocksRuntime/voidarg.c27
-rw-r--r--test/CMakeLists.txt65
-rw-r--r--test/asan/CMakeLists.txt156
-rw-r--r--test/asan/TestCases/Android/coverage-android.cc67
-rw-r--r--test/asan/TestCases/Android/lit.local.cfg11
-rw-r--r--test/asan/TestCases/Darwin/asan_gen_prefixes.cc14
-rw-r--r--test/asan/TestCases/Darwin/cstring_literals_regtest.mm23
-rw-r--r--test/asan/TestCases/Darwin/dyld_insert_libraries_reexec.cc33
-rw-r--r--test/asan/TestCases/Darwin/interception-in-shared-lib-test.cc32
-rw-r--r--test/asan/TestCases/Darwin/interface_symbols_darwin.c39
-rw-r--r--test/asan/TestCases/Darwin/lit.local.cfg9
-rw-r--r--test/asan/TestCases/Darwin/malloc_set_zone_name-mprotect.cc51
-rw-r--r--test/asan/TestCases/Darwin/malloc_zone-protected.cc20
-rw-r--r--test/asan/TestCases/Darwin/objc-odr.mm23
-rw-r--r--test/asan/TestCases/Darwin/reexec-insert-libraries-env.cc25
-rw-r--r--test/asan/TestCases/Darwin/suppressions-darwin.cc34
-rw-r--r--test/asan/TestCases/Darwin/unset-insert-libraries-on-exec.cc25
-rw-r--r--test/asan/TestCases/Helpers/blacklist-extra.cc5
-rw-r--r--test/asan/TestCases/Helpers/echo-env.cc19
-rw-r--r--test/asan/TestCases/Helpers/init-order-atexit-extra.cc16
-rw-r--r--test/asan/TestCases/Helpers/init-order-pthread-create-extra.cc2
-rw-r--r--test/asan/TestCases/Helpers/initialization-blacklist-extra.cc15
-rw-r--r--test/asan/TestCases/Helpers/initialization-blacklist-extra2.cc4
-rw-r--r--test/asan/TestCases/Helpers/initialization-blacklist.txt3
-rw-r--r--test/asan/TestCases/Helpers/initialization-bug-extra.cc5
-rw-r--r--test/asan/TestCases/Helpers/initialization-bug-extra2.cc6
-rw-r--r--test/asan/TestCases/Helpers/initialization-constexpr-extra.cc3
-rw-r--r--test/asan/TestCases/Helpers/initialization-nobug-extra.cc9
-rw-r--r--test/asan/TestCases/Helpers/lit.local.cfg3
-rw-r--r--test/asan/TestCases/Linux/asan-asm-stacktrace-test.cc33
-rw-r--r--test/asan/TestCases/Linux/asan_dlopen_test.cc15
-rw-r--r--test/asan/TestCases/Linux/asan_prelink_test.cc29
-rw-r--r--test/asan/TestCases/Linux/asan_preload_test-1.cc30
-rw-r--r--test/asan/TestCases/Linux/asan_preload_test-2.cc24
-rw-r--r--test/asan/TestCases/Linux/asan_rt_confict_test-1.cc13
-rw-r--r--test/asan/TestCases/Linux/asan_rt_confict_test-2.cc25
-rw-r--r--test/asan/TestCases/Linux/clang_gcc_abi.cc44
-rw-r--r--test/asan/TestCases/Linux/clone_test.cc45
-rw-r--r--test/asan/TestCases/Linux/coverage-and-lsan.cc20
-rw-r--r--test/asan/TestCases/Linux/coverage-caller-callee-total-count.cc41
-rw-r--r--test/asan/TestCases/Linux/coverage-caller-callee.cc74
-rw-r--r--test/asan/TestCases/Linux/coverage-direct-large.cc45
-rw-r--r--test/asan/TestCases/Linux/coverage-direct.cc44
-rw-r--r--test/asan/TestCases/Linux/coverage-disabled.cc18
-rw-r--r--test/asan/TestCases/Linux/coverage-fork-direct.cc38
-rw-r--r--test/asan/TestCases/Linux/coverage-fork.cc38
-rw-r--r--test/asan/TestCases/Linux/coverage-levels.cc20
-rw-r--r--test/asan/TestCases/Linux/coverage-maybe-open-file.cc31
-rw-r--r--test/asan/TestCases/Linux/coverage-module-unloaded.cc56
-rw-r--r--test/asan/TestCases/Linux/coverage-sandboxing.cc85
-rw-r--r--test/asan/TestCases/Linux/coverage-tracing.cc22
-rw-r--r--test/asan/TestCases/Linux/coverage.cc71
-rw-r--r--test/asan/TestCases/Linux/function-sections-are-bad.cc41
-rw-r--r--test/asan/TestCases/Linux/globals-gc-sections.cc13
-rw-r--r--test/asan/TestCases/Linux/initialization-bug-any-order.cc36
-rw-r--r--test/asan/TestCases/Linux/interception-in-shared-lib-test.cc32
-rw-r--r--test/asan/TestCases/Linux/interception_malloc_test.cc23
-rw-r--r--test/asan/TestCases/Linux/interception_readdir_r_test.cc62
-rw-r--r--test/asan/TestCases/Linux/interception_test.cc22
-rw-r--r--test/asan/TestCases/Linux/interface_symbols_linux.c35
-rw-r--r--test/asan/TestCases/Linux/kernel-area.cc24
-rw-r--r--test/asan/TestCases/Linux/leak.cc16
-rw-r--r--test/asan/TestCases/Linux/lit.local.cfg9
-rw-r--r--test/asan/TestCases/Linux/malloc-in-qsort.cc56
-rw-r--r--test/asan/TestCases/Linux/malloc_delete_mismatch.cc33
-rw-r--r--test/asan/TestCases/Linux/odr-violation.cc42
-rw-r--r--test/asan/TestCases/Linux/overflow-in-qsort.cc51
-rw-r--r--test/asan/TestCases/Linux/preinit_test.cc33
-rw-r--r--test/asan/TestCases/Linux/ptrace.cc56
-rw-r--r--test/asan/TestCases/Linux/rlimit_mmap_test.cc16
-rw-r--r--test/asan/TestCases/Linux/shmctl.cc27
-rw-r--r--test/asan/TestCases/Linux/sized_delete_test.cc93
-rw-r--r--test/asan/TestCases/Linux/stack-trace-dlclose.cc45
-rw-r--r--test/asan/TestCases/Linux/stress_dtls.c116
-rw-r--r--test/asan/TestCases/Linux/swapcontext_test.cc90
-rw-r--r--test/asan/TestCases/Linux/syscalls.cc25
-rw-r--r--test/asan/TestCases/Linux/uar_signals.cc70
-rw-r--r--test/asan/TestCases/Linux/unpoison_tls.cc35
-rw-r--r--test/asan/TestCases/Posix/allow_user_segv.cc59
-rw-r--r--test/asan/TestCases/Posix/asan-symbolize-sanity-test.cc63
-rw-r--r--test/asan/TestCases/Posix/asprintf.cc20
-rw-r--r--test/asan/TestCases/Posix/assign_large_valloc_to_global.cc9
-rw-r--r--test/asan/TestCases/Posix/glob.cc33
-rw-r--r--test/asan/TestCases/Posix/glob_test_root/aa0
-rw-r--r--test/asan/TestCases/Posix/glob_test_root/ab0
-rw-r--r--test/asan/TestCases/Posix/glob_test_root/ba0
-rw-r--r--test/asan/TestCases/Posix/init-order-dlopen.cc72
-rw-r--r--test/asan/TestCases/Posix/ioctl.cc24
-rw-r--r--test/asan/TestCases/Posix/large_allocator_unpoisons_on_free.cc39
-rw-r--r--test/asan/TestCases/Posix/lit.local.cfg9
-rw-r--r--test/asan/TestCases/Posix/new_array_cookie_test.cc24
-rw-r--r--test/asan/TestCases/Posix/new_array_cookie_uaf_test.cc38
-rw-r--r--test/asan/TestCases/Posix/new_array_cookie_with_new_from_class.cc38
-rw-r--r--test/asan/TestCases/Posix/readv.cc32
-rw-r--r--test/asan/TestCases/Posix/shared-lib-test.cc57
-rw-r--r--test/asan/TestCases/Posix/start-deactivated.cc69
-rw-r--r--test/asan/TestCases/Posix/strerror_r_test.cc14
-rw-r--r--test/asan/TestCases/Posix/tsd_dtor_leak.cc39
-rw-r--r--test/asan/TestCases/Posix/wait.cc45
-rw-r--r--test/asan/TestCases/Posix/wait4.cc43
-rw-r--r--test/asan/TestCases/Posix/waitid.cc28
-rw-r--r--test/asan/TestCases/Windows/aligned_mallocs.cc29
-rw-r--r--test/asan/TestCases/Windows/allocators_sanity.cc37
-rw-r--r--test/asan/TestCases/Windows/beginthreadex.cc21
-rw-r--r--test/asan/TestCases/Windows/bitfield.cc21
-rw-r--r--test/asan/TestCases/Windows/bitfield_uaf.cc34
-rw-r--r--test/asan/TestCases/Windows/calloc_left_oob.cc17
-rw-r--r--test/asan/TestCases/Windows/calloc_right_oob.cc17
-rw-r--r--test/asan/TestCases/Windows/calloc_uaf.cc20
-rw-r--r--test/asan/TestCases/Windows/crt_initializers.cc31
-rw-r--r--test/asan/TestCases/Windows/demangled_names.cc50
-rw-r--r--test/asan/TestCases/Windows/dll_aligned_mallocs.cc34
-rw-r--r--test/asan/TestCases/Windows/dll_allocators_sanity.cc39
-rw-r--r--test/asan/TestCases/Windows/dll_and_lib.cc19
-rw-r--r--test/asan/TestCases/Windows/dll_cerr.cc23
-rw-r--r--test/asan/TestCases/Windows/dll_host.cc49
-rw-r--r--test/asan/TestCases/Windows/dll_intercept_memchr.cc21
-rw-r--r--test/asan/TestCases/Windows/dll_intercept_memcpy.cc32
-rw-r--r--test/asan/TestCases/Windows/dll_intercept_memcpy_indirect.cc34
-rw-r--r--test/asan/TestCases/Windows/dll_intercept_memset.cc32
-rw-r--r--test/asan/TestCases/Windows/dll_intercept_strlen.cc28
-rw-r--r--test/asan/TestCases/Windows/dll_large_function.cc12
-rw-r--r--test/asan/TestCases/Windows/dll_malloc_left_oob.cc23
-rw-r--r--test/asan/TestCases/Windows/dll_malloc_uaf.cc28
-rw-r--r--test/asan/TestCases/Windows/dll_noreturn.cc28
-rw-r--r--test/asan/TestCases/Windows/dll_null_deref.cc18
-rw-r--r--test/asan/TestCases/Windows/dll_operator_array_new_left_oob.cc25
-rw-r--r--test/asan/TestCases/Windows/dll_operator_array_new_with_dtor_left_oob.cc33
-rw-r--r--test/asan/TestCases/Windows/dll_poison_unpoison.cc35
-rw-r--r--test/asan/TestCases/Windows/dll_seh.cc60
-rw-r--r--test/asan/TestCases/Windows/dll_stack_use_after_return.cc28
-rw-r--r--test/asan/TestCases/Windows/dll_thread_stack_array_left_oob.cc36
-rw-r--r--test/asan/TestCases/Windows/double_free.cc21
-rw-r--r--test/asan/TestCases/Windows/double_operator_delete.cc25
-rw-r--r--test/asan/TestCases/Windows/global_const_string.cc12
-rw-r--r--test/asan/TestCases/Windows/global_const_string_oob.cc20
-rw-r--r--test/asan/TestCases/Windows/hello_world.cc9
-rw-r--r--test/asan/TestCases/Windows/intercept_memcpy.cc31
-rw-r--r--test/asan/TestCases/Windows/intercept_strdup.cc27
-rw-r--r--test/asan/TestCases/Windows/intercept_strlen.cc27
-rw-r--r--test/asan/TestCases/Windows/lit.local.cfg14
-rw-r--r--test/asan/TestCases/Windows/longjmp.cc26
-rw-r--r--test/asan/TestCases/Windows/malloc_left_oob.cc17
-rw-r--r--test/asan/TestCases/Windows/malloc_right_oob.cc17
-rw-r--r--test/asan/TestCases/Windows/malloc_uaf.cc20
-rw-r--r--test/asan/TestCases/Windows/null_deref.cc15
-rw-r--r--test/asan/TestCases/Windows/null_deref_multiple_dlls.cc40
-rw-r--r--test/asan/TestCases/Windows/operator_array_new_left_oob.cc17
-rw-r--r--test/asan/TestCases/Windows/operator_array_new_right_oob.cc18
-rw-r--r--test/asan/TestCases/Windows/operator_array_new_uaf.cc24
-rw-r--r--test/asan/TestCases/Windows/operator_array_new_with_dtor_left_oob.cc25
-rw-r--r--test/asan/TestCases/Windows/operator_delete_wrong_argument.cc12
-rw-r--r--test/asan/TestCases/Windows/operator_new_left_oob.cc17
-rw-r--r--test/asan/TestCases/Windows/operator_new_right_oob.cc17
-rw-r--r--test/asan/TestCases/Windows/operator_new_uaf.cc22
-rw-r--r--test/asan/TestCases/Windows/realloc_left_oob.cc17
-rw-r--r--test/asan/TestCases/Windows/realloc_right_oob.cc17
-rw-r--r--test/asan/TestCases/Windows/realloc_uaf.cc20
-rw-r--r--test/asan/TestCases/Windows/report_after_syminitialize.cc19
-rw-r--r--test/asan/TestCases/Windows/seh.cc56
-rw-r--r--test/asan/TestCases/Windows/stack_array_left_oob.cc16
-rw-r--r--test/asan/TestCases/Windows/stack_array_right_oob.cc16
-rw-r--r--test/asan/TestCases/Windows/stack_array_sanity.cc12
-rw-r--r--test/asan/TestCases/Windows/stack_use_after_return.cc22
-rw-r--r--test/asan/TestCases/Windows/thread_simple.cc26
-rw-r--r--test/asan/TestCases/Windows/thread_stack_array_left_oob.cc27
-rw-r--r--test/asan/TestCases/Windows/thread_stack_array_right_oob.cc27
-rw-r--r--test/asan/TestCases/Windows/thread_stack_reuse.cc37
-rw-r--r--test/asan/TestCases/Windows/thread_stress.cc30
-rw-r--r--test/asan/TestCases/Windows/throw_catch.cc73
-rw-r--r--test/asan/TestCases/Windows/use_after_realloc.cc23
-rw-r--r--test/asan/TestCases/Windows/use_after_return_linkage.cc12
-rw-r--r--test/asan/TestCases/Windows/windows_h.cc7
-rw-r--r--test/asan/TestCases/Windows/wrong_downcast_on_heap.cc26
-rw-r--r--test/asan/TestCases/Windows/wrong_downcast_on_stack.cc26
-rw-r--r--test/asan/TestCases/alloca_big_alignment.cc18
-rw-r--r--test/asan/TestCases/alloca_detect_custom_size_.cc23
-rw-r--r--test/asan/TestCases/alloca_instruments_all_paddings.cc23
-rw-r--r--test/asan/TestCases/alloca_overflow_partial.cc18
-rw-r--r--test/asan/TestCases/alloca_overflow_right.cc18
-rw-r--r--test/asan/TestCases/alloca_safe_access.cc17
-rw-r--r--test/asan/TestCases/alloca_underflow_left.cc18
-rw-r--r--test/asan/TestCases/allocator_returns_null.cc83
-rw-r--r--test/asan/TestCases/asan_and_llvm_coverage_test.cc10
-rw-r--r--test/asan/TestCases/atexit_stats.cc18
-rw-r--r--test/asan/TestCases/blacklist.cc38
-rw-r--r--test/asan/TestCases/contiguous_container.cc75
-rw-r--r--test/asan/TestCases/contiguous_container_crash.cc41
-rw-r--r--test/asan/TestCases/current_allocated_bytes.cc44
-rw-r--r--test/asan/TestCases/debug_locate.cc80
-rw-r--r--test/asan/TestCases/debug_mapping.cc24
-rw-r--r--test/asan/TestCases/debug_ppc64_mapping.cc37
-rw-r--r--test/asan/TestCases/debug_report.cc48
-rw-r--r--test/asan/TestCases/debug_stacks.cc62
-rw-r--r--test/asan/TestCases/deep_call_stack.cc25
-rw-r--r--test/asan/TestCases/deep_stack_uaf.cc36
-rw-r--r--test/asan/TestCases/deep_tail_call.cc20
-rw-r--r--test/asan/TestCases/deep_thread_stack.cc58
-rw-r--r--test/asan/TestCases/default_blacklist.cc6
-rw-r--r--test/asan/TestCases/default_options.cc18
-rw-r--r--test/asan/TestCases/describe_address.cc19
-rw-r--r--test/asan/TestCases/dlclose-test.cc99
-rw-r--r--test/asan/TestCases/double-free.cc27
-rw-r--r--test/asan/TestCases/dump_instruction_bytes.cc20
-rw-r--r--test/asan/TestCases/force_inline_opt0.cc14
-rw-r--r--test/asan/TestCases/free_hook_realloc.cc37
-rw-r--r--test/asan/TestCases/frexp_interceptor.cc16
-rw-r--r--test/asan/TestCases/gc-test.cc50
-rw-r--r--test/asan/TestCases/global-demangle.cc17
-rw-r--r--test/asan/TestCases/global-location.cc38
-rw-r--r--test/asan/TestCases/global-overflow.cc21
-rw-r--r--test/asan/TestCases/heap-overflow-large.cc23
-rw-r--r--test/asan/TestCases/heap-overflow.cc24
-rw-r--r--test/asan/TestCases/heavy_uar_test.cc60
-rw-r--r--test/asan/TestCases/huge_negative_hea_oob.cc13
-rw-r--r--test/asan/TestCases/init-order-atexit.cc34
-rw-r--r--test/asan/TestCases/init-order-pthread-create.cc32
-rw-r--r--test/asan/TestCases/initialization-blacklist.cc29
-rw-r--r--test/asan/TestCases/initialization-bug.cc45
-rw-r--r--test/asan/TestCases/initialization-constexpr.cc27
-rw-r--r--test/asan/TestCases/initialization-nobug.cc48
-rw-r--r--test/asan/TestCases/inline.cc19
-rw-r--r--test/asan/TestCases/interception_failure_test.cc22
-rw-r--r--test/asan/TestCases/interface_test.cc10
-rw-r--r--test/asan/TestCases/intra-object-overflow.cc31
-rw-r--r--test/asan/TestCases/invalid-free.cc23
-rw-r--r--test/asan/TestCases/large_func_test.cc53
-rw-r--r--test/asan/TestCases/log-path_test.cc44
-rw-r--r--test/asan/TestCases/log_path_fork_test.cc.disabled22
-rw-r--r--test/asan/TestCases/longjmp.cc25
-rw-r--r--test/asan/TestCases/lsan_annotations.cc16
-rw-r--r--test/asan/TestCases/malloc_context_size.cc27
-rw-r--r--test/asan/TestCases/malloc_fill.cc22
-rw-r--r--test/asan/TestCases/max_redzone.cc26
-rw-r--r--test/asan/TestCases/memcmp_strict_test.cc15
-rw-r--r--test/asan/TestCases/memcmp_test.cc17
-rw-r--r--test/asan/TestCases/memset_test.cc71
-rw-r--r--test/asan/TestCases/mmap_limit_mb.cc33
-rw-r--r--test/asan/TestCases/no_asan_gen_globals.c11
-rw-r--r--test/asan/TestCases/null_deref.cc19
-rw-r--r--test/asan/TestCases/on_error_callback.cc19
-rw-r--r--test/asan/TestCases/partial_right.cc13
-rw-r--r--test/asan/TestCases/poison_partial.cc19
-rw-r--r--test/asan/TestCases/print_summary.cc14
-rw-r--r--test/asan/TestCases/printf-1.c25
-rw-r--r--test/asan/TestCases/printf-2.c27
-rw-r--r--test/asan/TestCases/printf-3.c22
-rw-r--r--test/asan/TestCases/printf-4.c23
-rw-r--r--test/asan/TestCases/printf-5.c25
-rw-r--r--test/asan/TestCases/sanity_check_pure_c.c21
-rw-r--r--test/asan/TestCases/sleep_before_dying.c10
-rw-r--r--test/asan/TestCases/stack-buffer-overflow-with-position.cc44
-rw-r--r--test/asan/TestCases/stack-buffer-overflow.cc16
-rw-r--r--test/asan/TestCases/stack-frame-demangle.cc22
-rw-r--r--test/asan/TestCases/stack-oob-frames.cc59
-rw-r--r--test/asan/TestCases/stack-overflow.cc114
-rw-r--r--test/asan/TestCases/stack-use-after-return.cc80
-rw-r--r--test/asan/TestCases/strdup_oob_test.cc20
-rw-r--r--test/asan/TestCases/strip_path_prefix.c12
-rw-r--r--test/asan/TestCases/strncpy-overflow.cc30
-rw-r--r--test/asan/TestCases/suppressions-function.cc29
-rw-r--r--test/asan/TestCases/suppressions-interceptor.cc24
-rw-r--r--test/asan/TestCases/suppressions-library.cc39
-rw-r--r--test/asan/TestCases/throw_call_test.cc52
-rw-r--r--test/asan/TestCases/throw_catch.cc64
-rw-r--r--test/asan/TestCases/throw_invoke_test.cc54
-rw-r--r--test/asan/TestCases/time_interceptor.cc22
-rw-r--r--test/asan/TestCases/uar_and_exceptions.cc43
-rw-r--r--test/asan/TestCases/unaligned_loads_and_stores.cc52
-rw-r--r--test/asan/TestCases/use-after-delete.cc31
-rw-r--r--test/asan/TestCases/use-after-free-right.cc36
-rw-r--r--test/asan/TestCases/use-after-free.cc36
-rw-r--r--test/asan/TestCases/use-after-poison.cc20
-rw-r--r--test/asan/TestCases/use-after-scope-dtor-order.cc26
-rw-r--r--test/asan/TestCases/use-after-scope-inlined.cc28
-rw-r--r--test/asan/TestCases/use-after-scope-nobug.cc15
-rw-r--r--test/asan/TestCases/use-after-scope-temp.cc29
-rw-r--r--test/asan/TestCases/use-after-scope.cc17
-rw-r--r--test/asan/TestCases/zero_page_pc.cc12
-rw-r--r--test/asan/Unit/lit.site.cfg.in24
-rw-r--r--test/asan/android_commands/android_common.py29
-rwxr-xr-xtest/asan/android_commands/android_compile.py36
-rwxr-xr-xtest/asan/android_commands/android_run.py34
-rw-r--r--test/asan/lit.cfg153
-rw-r--r--test/asan/lit.site.cfg.in19
-rw-r--r--test/builtins/Unit/absvdi2_test.c (renamed from test/Unit/absvdi2_test.c)0
-rw-r--r--test/builtins/Unit/absvsi2_test.c (renamed from test/Unit/absvsi2_test.c)0
-rw-r--r--test/builtins/Unit/absvti2_test.c (renamed from test/Unit/absvti2_test.c)6
-rw-r--r--test/builtins/Unit/adddf3vfp_test.c (renamed from test/Unit/adddf3vfp_test.c)0
-rw-r--r--test/builtins/Unit/addsf3vfp_test.c (renamed from test/Unit/addsf3vfp_test.c)0
-rw-r--r--test/builtins/Unit/addtf3_test.c81
-rw-r--r--test/builtins/Unit/addvdi3_test.c (renamed from test/Unit/addvdi3_test.c)0
-rw-r--r--test/builtins/Unit/addvsi3_test.c (renamed from test/Unit/addvsi3_test.c)0
-rw-r--r--test/builtins/Unit/addvti3_test.c (renamed from test/Unit/addvti3_test.c)6
-rw-r--r--test/builtins/Unit/ashldi3_test.c (renamed from test/Unit/ashldi3_test.c)0
-rw-r--r--test/builtins/Unit/ashlti3_test.c (renamed from test/Unit/ashlti3_test.c)6
-rw-r--r--test/builtins/Unit/ashrdi3_test.c (renamed from test/Unit/ashrdi3_test.c)0
-rw-r--r--test/builtins/Unit/ashrti3_test.c (renamed from test/Unit/ashrti3_test.c)6
-rw-r--r--test/builtins/Unit/bswapdi2_test.c (renamed from test/Unit/bswapdi2_test.c)0
-rw-r--r--test/builtins/Unit/bswapsi2_test.c (renamed from test/Unit/bswapsi2_test.c)0
-rw-r--r--test/builtins/Unit/clear_cache_test.c (renamed from test/Unit/clear_cache_test.c)0
-rw-r--r--test/builtins/Unit/clzdi2_test.c (renamed from test/Unit/clzdi2_test.c)0
-rw-r--r--test/builtins/Unit/clzsi2_test.c (renamed from test/Unit/clzsi2_test.c)0
-rw-r--r--test/builtins/Unit/clzti2_test.c (renamed from test/Unit/clzti2_test.c)6
-rw-r--r--test/builtins/Unit/cmpdi2_test.c (renamed from test/Unit/cmpdi2_test.c)0
-rw-r--r--test/builtins/Unit/cmpti2_test.c (renamed from test/Unit/cmpti2_test.c)6
-rw-r--r--test/builtins/Unit/comparedf2_test.c (renamed from test/Unit/comparedf2_test.c)0
-rw-r--r--test/builtins/Unit/comparesf2_test.c (renamed from test/Unit/comparesf2_test.c)0
-rw-r--r--test/builtins/Unit/ctzdi2_test.c (renamed from test/Unit/ctzdi2_test.c)0
-rw-r--r--test/builtins/Unit/ctzsi2_test.c (renamed from test/Unit/ctzsi2_test.c)0
-rw-r--r--test/builtins/Unit/ctzti2_test.c (renamed from test/Unit/ctzti2_test.c)6
-rw-r--r--test/builtins/Unit/divdc3_test.c (renamed from test/Unit/divdc3_test.c)0
-rw-r--r--test/builtins/Unit/divdf3vfp_test.c (renamed from test/Unit/divdf3vfp_test.c)0
-rw-r--r--test/builtins/Unit/divdi3_test.c (renamed from test/Unit/divdi3_test.c)0
-rw-r--r--test/builtins/Unit/divmodsi4_test.c (renamed from test/Unit/divmodsi4_test.c)0
-rw-r--r--test/builtins/Unit/divsc3_test.c (renamed from test/Unit/divsc3_test.c)0
-rw-r--r--test/builtins/Unit/divsf3vfp_test.c (renamed from test/Unit/divsf3vfp_test.c)0
-rw-r--r--test/builtins/Unit/divsi3_test.c (renamed from test/Unit/divsi3_test.c)0
-rw-r--r--test/builtins/Unit/divtc3_test.c (renamed from test/Unit/divtc3_test.c)0
-rw-r--r--test/builtins/Unit/divtf3_test.c94
-rw-r--r--test/builtins/Unit/divti3_test.c (renamed from test/Unit/divti3_test.c)6
-rw-r--r--test/builtins/Unit/divxc3_test.c (renamed from test/Unit/divxc3_test.c)0
-rw-r--r--test/builtins/Unit/enable_execute_stack_test.c (renamed from test/Unit/enable_execute_stack_test.c)0
-rw-r--r--test/builtins/Unit/endianness.h (renamed from test/Unit/endianness.h)0
-rw-r--r--test/builtins/Unit/eqdf2vfp_test.c (renamed from test/Unit/eqdf2vfp_test.c)0
-rw-r--r--test/builtins/Unit/eqsf2vfp_test.c (renamed from test/Unit/eqsf2vfp_test.c)0
-rw-r--r--test/builtins/Unit/eqtf2_test.c89
-rw-r--r--test/builtins/Unit/extebdsfdf2vfp_test.c (renamed from test/Unit/extebdsfdf2vfp_test.c)0
-rw-r--r--test/builtins/Unit/extenddftf2_test.c82
-rw-r--r--test/builtins/Unit/extendsftf2_test.c83
-rw-r--r--test/builtins/Unit/ffsdi2_test.c (renamed from test/Unit/ffsdi2_test.c)0
-rw-r--r--test/builtins/Unit/ffsti2_test.c (renamed from test/Unit/ffsti2_test.c)6
-rw-r--r--test/builtins/Unit/fixdfdi_test.c (renamed from test/Unit/fixdfdi_test.c)0
-rw-r--r--test/builtins/Unit/fixdfsivfp_test.c (renamed from test/Unit/fixdfsivfp_test.c)0
-rw-r--r--test/builtins/Unit/fixdfti_test.c (renamed from test/Unit/fixdfti_test.c)6
-rw-r--r--test/builtins/Unit/fixsfdi_test.c (renamed from test/Unit/fixsfdi_test.c)0
-rw-r--r--test/builtins/Unit/fixsfsivfp_test.c (renamed from test/Unit/fixsfsivfp_test.c)0
-rw-r--r--test/builtins/Unit/fixsfti_test.c (renamed from test/Unit/fixsfti_test.c)6
-rw-r--r--test/builtins/Unit/fixunsdfdi_test.c (renamed from test/Unit/fixunsdfdi_test.c)0
-rw-r--r--test/builtins/Unit/fixunsdfsi_test.c (renamed from test/Unit/fixunsdfsi_test.c)0
-rw-r--r--test/builtins/Unit/fixunsdfsivfp_test.c (renamed from test/Unit/fixunsdfsivfp_test.c)0
-rw-r--r--test/builtins/Unit/fixunsdfti_test.c (renamed from test/Unit/fixunsdfti_test.c)4
-rw-r--r--test/builtins/Unit/fixunssfdi_test.c (renamed from test/Unit/fixunssfdi_test.c)0
-rw-r--r--test/builtins/Unit/fixunssfsi_test.c (renamed from test/Unit/fixunssfsi_test.c)0
-rw-r--r--test/builtins/Unit/fixunssfsivfp_test.c (renamed from test/Unit/fixunssfsivfp_test.c)0
-rw-r--r--test/builtins/Unit/fixunssfti_test.c (renamed from test/Unit/fixunssfti_test.c)6
-rw-r--r--test/builtins/Unit/fixunstfdi_test.c (renamed from test/Unit/fixunstfdi_test.c)0
-rw-r--r--test/builtins/Unit/fixunsxfdi_test.c (renamed from test/Unit/fixunsxfdi_test.c)0
-rw-r--r--test/builtins/Unit/fixunsxfsi_test.c (renamed from test/Unit/fixunsxfsi_test.c)0
-rw-r--r--test/builtins/Unit/fixunsxfti_test.c (renamed from test/Unit/fixunsxfti_test.c)6
-rw-r--r--test/builtins/Unit/fixxfdi_test.c (renamed from test/Unit/fixxfdi_test.c)0
-rw-r--r--test/builtins/Unit/fixxfti_test.c (renamed from test/Unit/fixxfti_test.c)6
-rw-r--r--test/builtins/Unit/floatdidf_test.c (renamed from test/Unit/floatdidf_test.c)0
-rw-r--r--test/builtins/Unit/floatdisf_test.c (renamed from test/Unit/floatdisf_test.c)0
-rw-r--r--test/builtins/Unit/floatdixf_test.c (renamed from test/Unit/floatdixf_test.c)0
-rw-r--r--test/builtins/Unit/floatsidfvfp_test.c (renamed from test/Unit/floatsidfvfp_test.c)0
-rw-r--r--test/builtins/Unit/floatsisfvfp_test.c (renamed from test/Unit/floatsisfvfp_test.c)0
-rw-r--r--test/builtins/Unit/floatsitf_test.c58
-rw-r--r--test/builtins/Unit/floattidf_test.c (renamed from test/Unit/floattidf_test.c)6
-rw-r--r--test/builtins/Unit/floattisf_test.c (renamed from test/Unit/floattisf_test.c)6
-rw-r--r--test/builtins/Unit/floattixf_test.c (renamed from test/Unit/floattixf_test.c)6
-rw-r--r--test/builtins/Unit/floatundidf_test.c (renamed from test/Unit/floatundidf_test.c)0
-rw-r--r--test/builtins/Unit/floatundisf_test.c (renamed from test/Unit/floatundisf_test.c)0
-rw-r--r--test/builtins/Unit/floatundixf_test.c (renamed from test/Unit/floatundixf_test.c)0
-rw-r--r--test/builtins/Unit/floatunsitf_test.c55
-rw-r--r--test/builtins/Unit/floatunssidfvfp_test.c (renamed from test/Unit/floatunssidfvfp_test.c)0
-rw-r--r--test/builtins/Unit/floatunssisfvfp_test.c (renamed from test/Unit/floatunssisfvfp_test.c)0
-rw-r--r--test/builtins/Unit/floatuntidf_test.c (renamed from test/Unit/floatuntidf_test.c)6
-rw-r--r--test/builtins/Unit/floatuntisf_test.c (renamed from test/Unit/floatuntisf_test.c)6
-rw-r--r--test/builtins/Unit/floatuntixf_test.c (renamed from test/Unit/floatuntixf_test.c)6
-rw-r--r--test/builtins/Unit/fp_test.h223
-rw-r--r--test/builtins/Unit/gcc_personality_test.c (renamed from test/Unit/gcc_personality_test.c)0
-rw-r--r--test/builtins/Unit/gcc_personality_test_helper.cxx (renamed from test/Unit/gcc_personality_test_helper.cxx)0
-rw-r--r--test/builtins/Unit/gedf2vfp_test.c (renamed from test/Unit/gedf2vfp_test.c)0
-rw-r--r--test/builtins/Unit/gesf2vfp_test.c (renamed from test/Unit/gesf2vfp_test.c)0
-rw-r--r--test/builtins/Unit/getf2_test.c89
-rw-r--r--test/builtins/Unit/gtdf2vfp_test.c (renamed from test/Unit/gtdf2vfp_test.c)0
-rw-r--r--test/builtins/Unit/gtsf2vfp_test.c (renamed from test/Unit/gtsf2vfp_test.c)0
-rw-r--r--test/builtins/Unit/gttf2_test.c89
-rw-r--r--test/builtins/Unit/ledf2vfp_test.c (renamed from test/Unit/ledf2vfp_test.c)0
-rw-r--r--test/builtins/Unit/lesf2vfp_test.c (renamed from test/Unit/lesf2vfp_test.c)0
-rw-r--r--test/builtins/Unit/letf2_test.c89
-rw-r--r--test/builtins/Unit/lshrdi3_test.c (renamed from test/Unit/lshrdi3_test.c)0
-rw-r--r--test/builtins/Unit/lshrti3_test.c (renamed from test/Unit/lshrti3_test.c)6
-rw-r--r--test/builtins/Unit/ltdf2vfp_test.c (renamed from test/Unit/ltdf2vfp_test.c)0
-rw-r--r--test/builtins/Unit/ltsf2vfp_test.c (renamed from test/Unit/ltsf2vfp_test.c)0
-rw-r--r--test/builtins/Unit/lttf2_test.c89
-rw-r--r--test/builtins/Unit/moddi3_test.c (renamed from test/Unit/moddi3_test.c)0
-rw-r--r--test/builtins/Unit/modsi3_test.c (renamed from test/Unit/modsi3_test.c)0
-rw-r--r--test/builtins/Unit/modti3_test.c (renamed from test/Unit/modti3_test.c)6
-rw-r--r--test/builtins/Unit/muldc3_test.c (renamed from test/Unit/muldc3_test.c)0
-rw-r--r--test/builtins/Unit/muldf3vfp_test.c (renamed from test/Unit/muldf3vfp_test.c)0
-rw-r--r--test/builtins/Unit/muldi3_test.c (renamed from test/Unit/muldi3_test.c)0
-rw-r--r--test/builtins/Unit/mulodi4_test.c (renamed from test/Unit/mulodi4_test.c)0
-rw-r--r--test/builtins/Unit/mulosi4_test.c (renamed from test/Unit/mulosi4_test.c)0
-rw-r--r--test/builtins/Unit/muloti4_test.c (renamed from test/Unit/muloti4_test.c)6
-rw-r--r--test/builtins/Unit/mulsc3_test.c (renamed from test/Unit/mulsc3_test.c)0
-rw-r--r--test/builtins/Unit/mulsf3vfp_test.c (renamed from test/Unit/mulsf3vfp_test.c)0
-rw-r--r--test/builtins/Unit/multc3_test.c (renamed from test/Unit/multc3_test.c)0
-rw-r--r--test/builtins/Unit/multf3_test.c95
-rw-r--r--test/builtins/Unit/multi3_test.c (renamed from test/Unit/multi3_test.c)6
-rw-r--r--test/builtins/Unit/mulvdi3_test.c (renamed from test/Unit/mulvdi3_test.c)0
-rw-r--r--test/builtins/Unit/mulvsi3_test.c (renamed from test/Unit/mulvsi3_test.c)0
-rw-r--r--test/builtins/Unit/mulvti3_test.c (renamed from test/Unit/mulvti3_test.c)6
-rw-r--r--test/builtins/Unit/mulxc3_test.c (renamed from test/Unit/mulxc3_test.c)0
-rw-r--r--test/builtins/Unit/nedf2vfp_test.c (renamed from test/Unit/nedf2vfp_test.c)0
-rw-r--r--test/builtins/Unit/negdf2vfp_test.c (renamed from test/Unit/negdf2vfp_test.c)0
-rw-r--r--test/builtins/Unit/negdi2_test.c (renamed from test/Unit/negdi2_test.c)0
-rw-r--r--test/builtins/Unit/negsf2vfp_test.c (renamed from test/Unit/negsf2vfp_test.c)0
-rw-r--r--test/builtins/Unit/negti2_test.c (renamed from test/Unit/negti2_test.c)6
-rw-r--r--test/builtins/Unit/negvdi2_test.c (renamed from test/Unit/negvdi2_test.c)0
-rw-r--r--test/builtins/Unit/negvsi2_test.c (renamed from test/Unit/negvsi2_test.c)0
-rw-r--r--test/builtins/Unit/negvti2_test.c (renamed from test/Unit/negvti2_test.c)6
-rw-r--r--test/builtins/Unit/nesf2vfp_test.c (renamed from test/Unit/nesf2vfp_test.c)0
-rw-r--r--test/builtins/Unit/netf2_test.c89
-rw-r--r--test/builtins/Unit/paritydi2_test.c (renamed from test/Unit/paritydi2_test.c)0
-rw-r--r--test/builtins/Unit/paritysi2_test.c (renamed from test/Unit/paritysi2_test.c)0
-rw-r--r--test/builtins/Unit/parityti2_test.c (renamed from test/Unit/parityti2_test.c)6
-rw-r--r--test/builtins/Unit/popcountdi2_test.c (renamed from test/Unit/popcountdi2_test.c)0
-rw-r--r--test/builtins/Unit/popcountsi2_test.c (renamed from test/Unit/popcountsi2_test.c)0
-rw-r--r--test/builtins/Unit/popcountti2_test.c (renamed from test/Unit/popcountti2_test.c)6
-rw-r--r--test/builtins/Unit/powidf2_test.c (renamed from test/Unit/powidf2_test.c)0
-rw-r--r--test/builtins/Unit/powisf2_test.c (renamed from test/Unit/powisf2_test.c)0
-rw-r--r--test/builtins/Unit/powitf2_test.c (renamed from test/Unit/powitf2_test.c)0
-rw-r--r--test/builtins/Unit/powixf2_test.c (renamed from test/Unit/powixf2_test.c)0
-rw-r--r--test/builtins/Unit/ppc/DD.h (renamed from test/Unit/ppc/DD.h)0
-rw-r--r--test/builtins/Unit/ppc/fixtfdi_test.c (renamed from test/Unit/ppc/fixtfdi_test.c)0
-rw-r--r--test/builtins/Unit/ppc/floatditf_test.c (renamed from test/Unit/ppc/floatditf_test.c)0
-rw-r--r--test/builtins/Unit/ppc/floatditf_test.h (renamed from test/Unit/ppc/floatditf_test.h)0
-rw-r--r--test/builtins/Unit/ppc/floatunditf_test.c (renamed from test/Unit/ppc/floatunditf_test.c)0
-rw-r--r--test/builtins/Unit/ppc/floatunditf_test.h (renamed from test/Unit/ppc/floatunditf_test.h)0
-rw-r--r--test/builtins/Unit/ppc/qadd_test.c (renamed from test/Unit/ppc/qadd_test.c)0
-rw-r--r--test/builtins/Unit/ppc/qdiv_test.c (renamed from test/Unit/ppc/qdiv_test.c)0
-rw-r--r--test/builtins/Unit/ppc/qmul_test.c (renamed from test/Unit/ppc/qmul_test.c)0
-rw-r--r--test/builtins/Unit/ppc/qsub_test.c (renamed from test/Unit/ppc/qsub_test.c)0
-rwxr-xr-xtest/builtins/Unit/ppc/test (renamed from test/Unit/ppc/test)0
-rw-r--r--test/builtins/Unit/subdf3vfp_test.c (renamed from test/Unit/subdf3vfp_test.c)0
-rw-r--r--test/builtins/Unit/subsf3vfp_test.c (renamed from test/Unit/subsf3vfp_test.c)0
-rw-r--r--test/builtins/Unit/subtf3_test.c74
-rw-r--r--test/builtins/Unit/subvdi3_test.c (renamed from test/Unit/subvdi3_test.c)0
-rw-r--r--test/builtins/Unit/subvsi3_test.c (renamed from test/Unit/subvsi3_test.c)0
-rw-r--r--test/builtins/Unit/subvti3_test.c (renamed from test/Unit/subvti3_test.c)6
-rwxr-xr-xtest/builtins/Unit/test (renamed from test/Unit/test)0
-rw-r--r--test/builtins/Unit/trampoline_setup_test.c (renamed from test/Unit/trampoline_setup_test.c)0
-rw-r--r--test/builtins/Unit/truncdfsf2vfp_test.c (renamed from test/Unit/truncdfsf2vfp_test.c)0
-rw-r--r--test/builtins/Unit/trunctfdf2_test.c76
-rw-r--r--test/builtins/Unit/trunctfsf2_test.c75
-rw-r--r--test/builtins/Unit/ucmpdi2_test.c (renamed from test/Unit/ucmpdi2_test.c)0
-rw-r--r--test/builtins/Unit/ucmpti2_test.c (renamed from test/Unit/ucmpti2_test.c)6
-rw-r--r--test/builtins/Unit/udivdi3_test.c (renamed from test/Unit/udivdi3_test.c)0
-rw-r--r--test/builtins/Unit/udivmoddi4_test.c (renamed from test/Unit/udivmoddi4_test.c)0
-rw-r--r--test/builtins/Unit/udivmodsi4_test.c (renamed from test/Unit/udivmodsi4_test.c)0
-rw-r--r--test/builtins/Unit/udivmodti4_test.c (renamed from test/Unit/udivmodti4_test.c)6
-rw-r--r--test/builtins/Unit/udivsi3_test.c (renamed from test/Unit/udivsi3_test.c)0
-rw-r--r--test/builtins/Unit/udivti3_test.c (renamed from test/Unit/udivti3_test.c)6
-rw-r--r--test/builtins/Unit/umoddi3_test.c (renamed from test/Unit/umoddi3_test.c)0
-rw-r--r--test/builtins/Unit/umodsi3_test.c (renamed from test/Unit/umodsi3_test.c)0
-rw-r--r--test/builtins/Unit/umodti3_test.c (renamed from test/Unit/umodti3_test.c)6
-rw-r--r--test/builtins/Unit/unorddf2vfp_test.c (renamed from test/Unit/unorddf2vfp_test.c)0
-rw-r--r--test/builtins/Unit/unordsf2vfp_test.c (renamed from test/Unit/unordsf2vfp_test.c)0
-rw-r--r--test/builtins/Unit/unordtf2_test.c65
-rw-r--r--test/builtins/timing/ashldi3.c (renamed from test/timing/ashldi3.c)0
-rw-r--r--test/builtins/timing/ashrdi3.c (renamed from test/timing/ashrdi3.c)0
-rw-r--r--test/builtins/timing/divdi3.c (renamed from test/timing/divdi3.c)0
-rw-r--r--test/builtins/timing/floatdidf.c (renamed from test/timing/floatdidf.c)0
-rw-r--r--test/builtins/timing/floatdisf.c (renamed from test/timing/floatdisf.c)0
-rw-r--r--test/builtins/timing/floatdixf.c (renamed from test/timing/floatdixf.c)0
-rw-r--r--test/builtins/timing/floatundidf.c (renamed from test/timing/floatundidf.c)0
-rw-r--r--test/builtins/timing/floatundisf.c (renamed from test/timing/floatundisf.c)0
-rw-r--r--test/builtins/timing/floatundixf.c (renamed from test/timing/floatundixf.c)0
-rw-r--r--test/builtins/timing/lshrdi3.c (renamed from test/timing/lshrdi3.c)0
-rw-r--r--test/builtins/timing/moddi3.c (renamed from test/timing/moddi3.c)0
-rw-r--r--test/builtins/timing/modsi3.c (renamed from test/timing/modsi3.c)0
-rw-r--r--test/builtins/timing/muldi3.c (renamed from test/timing/muldi3.c)0
-rw-r--r--test/builtins/timing/negdi2.c (renamed from test/timing/negdi2.c)0
-rwxr-xr-xtest/builtins/timing/time (renamed from test/timing/time)0
-rw-r--r--test/builtins/timing/timing.h (renamed from test/timing/timing.h)0
-rw-r--r--test/builtins/timing/udivdi3.c (renamed from test/timing/udivdi3.c)0
-rw-r--r--test/builtins/timing/umoddi3.c (renamed from test/timing/umoddi3.c)0
-rw-r--r--test/dfsan/CMakeLists.txt15
-rw-r--r--test/dfsan/Inputs/flags_abilist.txt10
-rw-r--r--test/dfsan/basic.c28
-rw-r--r--test/dfsan/custom.cc958
-rw-r--r--test/dfsan/dump_labels.c69
-rw-r--r--test/dfsan/flags.c24
-rw-r--r--test/dfsan/fncall.c26
-rw-r--r--test/dfsan/label_count.c75
-rw-r--r--test/dfsan/lit.cfg26
-rw-r--r--test/dfsan/lit.site.cfg.in5
-rw-r--r--test/dfsan/propagate.c47
-rw-r--r--test/dfsan/vararg.c24
-rw-r--r--test/dfsan/write_callback.c110
-rw-r--r--test/lit.common.cfg89
-rw-r--r--test/lit.common.configured.in38
-rw-r--r--test/lsan/CMakeLists.txt23
-rw-r--r--test/lsan/TestCases/cleanup_in_tsd_destructor.cc45
-rw-r--r--test/lsan/TestCases/disabler.cc23
-rw-r--r--test/lsan/TestCases/disabler_in_tsd_destructor.cc38
-rw-r--r--test/lsan/TestCases/do_leak_check_override.cc36
-rw-r--r--test/lsan/TestCases/fork.cc24
-rw-r--r--test/lsan/TestCases/fork_threaded.cc43
-rw-r--r--test/lsan/TestCases/high_allocator_contention.cc48
-rw-r--r--test/lsan/TestCases/ignore_object.cc24
-rw-r--r--test/lsan/TestCases/ignore_object_errors.cc22
-rw-r--r--test/lsan/TestCases/large_allocation_leak.cc18
-rw-r--r--test/lsan/TestCases/leak_check_at_exit.cc21
-rw-r--r--test/lsan/TestCases/leak_check_before_thread_started.cc32
-rw-r--r--test/lsan/TestCases/link_turned_off.cc24
-rw-r--r--test/lsan/TestCases/new_array_with_dtor_0.cc19
-rw-r--r--test/lsan/TestCases/pointer_to_self.cc18
-rw-r--r--test/lsan/TestCases/print_suppressions.cc33
-rw-r--r--test/lsan/TestCases/register_root_region.cc32
-rw-r--r--test/lsan/TestCases/sanity_check_pure_c.c10
-rw-r--r--test/lsan/TestCases/stale_stack_leak.cc43
-rw-r--r--test/lsan/TestCases/suppressions_default.cc28
-rw-r--r--test/lsan/TestCases/suppressions_file.cc26
-rw-r--r--test/lsan/TestCases/swapcontext.cc47
-rw-r--r--test/lsan/TestCases/use_after_return.cc23
-rw-r--r--test/lsan/TestCases/use_globals_initialized.cc21
-rw-r--r--test/lsan/TestCases/use_globals_uninitialized.cc21
-rw-r--r--test/lsan/TestCases/use_poisoned_asan.cc25
-rw-r--r--test/lsan/TestCases/use_registers.cc52
-rw-r--r--test/lsan/TestCases/use_stacks.cc20
-rw-r--r--test/lsan/TestCases/use_stacks_threaded.cc37
-rw-r--r--test/lsan/TestCases/use_tls_dynamic.cc50
-rw-r--r--test/lsan/TestCases/use_tls_pthread_specific_dynamic.cc37
-rw-r--r--test/lsan/TestCases/use_tls_pthread_specific_static.cc31
-rw-r--r--test/lsan/TestCases/use_tls_static.cc21
-rw-r--r--test/lsan/TestCases/use_unaligned.cc23
-rw-r--r--test/lsan/lit.common.cfg51
-rw-r--r--test/lsan/lit.site.cfg.in8
-rw-r--r--test/msan/CMakeLists.txt23
-rw-r--r--test/msan/Linux/getresid.cc25
-rw-r--r--test/msan/Linux/glob.cc27
-rw-r--r--test/msan/Linux/glob_altdirfunc.cc78
-rw-r--r--test/msan/Linux/glob_nomatch.cc21
-rw-r--r--test/msan/Linux/glob_test_root/aa0
-rw-r--r--test/msan/Linux/glob_test_root/ab0
-rw-r--r--test/msan/Linux/glob_test_root/ba0
-rw-r--r--test/msan/Linux/lit.local.cfg9
-rw-r--r--test/msan/Linux/sunrpc.cc40
-rw-r--r--test/msan/Linux/sunrpc_bytes.cc38
-rw-r--r--test/msan/Linux/sunrpc_string.cc35
-rw-r--r--test/msan/Linux/syscalls.cc115
-rw-r--r--test/msan/Linux/tcgetattr.cc21
-rw-r--r--test/msan/Linux/xattr.cc145
-rw-r--r--test/msan/Linux/xattr_test_root/a0
-rw-r--r--test/msan/Unit/lit.site.cfg.in14
-rw-r--r--test/msan/allocator_returns_null.cc81
-rw-r--r--test/msan/backtrace.cc26
-rw-r--r--test/msan/c-strdup.c17
-rw-r--r--test/msan/chained_origin.cc66
-rw-r--r--test/msan/chained_origin_empty_stack.cc34
-rw-r--r--test/msan/chained_origin_limits.cc178
-rw-r--r--test/msan/chained_origin_memcpy.cc61
-rw-r--r--test/msan/chained_origin_with_signals.cc36
-rw-r--r--test/msan/check_mem_is_initialized.cc33
-rw-r--r--test/msan/coverage-levels.cc28
-rw-r--r--test/msan/cxa_atexit.cc28
-rw-r--r--test/msan/death-callback.cc39
-rw-r--r--test/msan/default_blacklist.cc3
-rw-r--r--test/msan/dlerror.cc14
-rw-r--r--test/msan/dso-origin.cc48
-rw-r--r--test/msan/dtls_test.c60
-rw-r--r--test/msan/errno.cc17
-rw-r--r--test/msan/fork.cc121
-rw-r--r--test/msan/ftime.cc14
-rw-r--r--test/msan/getaddrinfo-positive.cc23
-rw-r--r--test/msan/getaddrinfo.cc24
-rw-r--r--test/msan/getc_unlocked.c32
-rw-r--r--test/msan/getline.cc36
-rw-r--r--test/msan/heap-origin.cc31
-rw-r--r--test/msan/iconv.cc48
-rw-r--r--test/msan/if_indextoname.cc23
-rw-r--r--test/msan/ifaddrs.cc50
-rw-r--r--test/msan/initgroups.cc11
-rw-r--r--test/msan/inline.cc20
-rw-r--r--test/msan/insertvalue_origin.cc35
-rw-r--r--test/msan/ioctl.cc20
-rw-r--r--test/msan/ioctl_custom.cc33
-rw-r--r--test/msan/ioctl_sound.cc29
-rw-r--r--test/msan/keep-going-dso.cc33
-rw-r--r--test/msan/keep-going.cc34
-rw-r--r--test/msan/lit.cfg30
-rw-r--r--test/msan/lit.site.cfg.in5
-rw-r--r--test/msan/mallinfo.cc12
-rw-r--r--test/msan/mktime.cc26
-rw-r--r--test/msan/mmap_below_shadow.cc28
-rw-r--r--test/msan/msan_check_mem_is_initialized.cc28
-rw-r--r--test/msan/msan_dump_shadow.cc22
-rw-r--r--test/msan/msan_print_shadow.cc122
-rw-r--r--test/msan/msan_print_shadow2.cc49
-rw-r--r--test/msan/msan_print_shadow3.cc16
-rw-r--r--test/msan/mul_by_const.cc27
-rw-r--r--test/msan/no_sanitize_memory.cc34
-rw-r--r--test/msan/no_sanitize_memory_prop.cc24
-rw-r--r--test/msan/obstack.cc37
-rw-r--r--test/msan/param_tls_limit.cc74
-rw-r--r--test/msan/poison_in_free.cc16
-rw-r--r--test/msan/print_stats.cc45
-rw-r--r--test/msan/pthread_getattr_np_deadlock.cc22
-rw-r--r--test/msan/rand_r.cc18
-rw-r--r--test/msan/readdir64.cc27
-rw-r--r--test/msan/report-demangling.cc19
-rw-r--r--test/msan/scandir.cc56
-rw-r--r--test/msan/scandir_null.cc34
-rw-r--r--test/msan/scandir_test_root/aaa0
-rw-r--r--test/msan/scandir_test_root/aab0
-rw-r--r--test/msan/scandir_test_root/bbb0
-rw-r--r--test/msan/select.cc22
-rw-r--r--test/msan/select_float_origin.cc24
-rw-r--r--test/msan/select_origin.cc22
-rw-r--r--test/msan/setlocale.cc13
-rw-r--r--test/msan/signal_stress_test.cc71
-rw-r--r--test/msan/sigwait.cc30
-rw-r--r--test/msan/sigwaitinfo.cc31
-rw-r--r--test/msan/stack-origin.cc31
-rw-r--r--test/msan/stack-origin2.cc41
-rw-r--r--test/msan/strerror_r-non-gnu.c18
-rw-r--r--test/msan/strlen_of_shadow.cc24
-rw-r--r--test/msan/strxfrm.cc15
-rw-r--r--test/msan/sync_lock_set_and_test.cc7
-rw-r--r--test/msan/textdomain.cc12
-rw-r--r--test/msan/times.cc20
-rw-r--r--test/msan/tls_reuse.cc26
-rw-r--r--test/msan/tsearch.cc36
-rw-r--r--test/msan/tzset.cc16
-rw-r--r--test/msan/unaligned_read_origin.cc16
-rw-r--r--test/msan/unpoison_string.cc16
-rw-r--r--test/msan/use-after-free.cc34
-rw-r--r--test/msan/vector_cvt.cc23
-rw-r--r--test/msan/vector_select.cc13
-rw-r--r--test/profile/CMakeLists.txt16
-rw-r--r--test/profile/Inputs/instrprof-dlopen-func.c1
-rw-r--r--test/profile/Inputs/instrprof-dlopen-func2.c1
-rw-r--r--test/profile/Inputs/instrprof-dlopen-main.c47
-rw-r--r--test/profile/Inputs/instrprof-dynamic-a.cpp7
-rw-r--r--test/profile/Inputs/instrprof-dynamic-b.cpp7
-rw-r--r--test/profile/Inputs/instrprof-dynamic-header.h5
-rw-r--r--test/profile/Inputs/instrprof-dynamic-main.cpp9
-rw-r--r--test/profile/instrprof-basic.c31
-rw-r--r--test/profile/instrprof-dlopen.test34
-rw-r--r--test/profile/instrprof-dynamic-one-shared.test23
-rw-r--r--test/profile/instrprof-dynamic-two-shared.test24
-rw-r--r--test/profile/instrprof-reset-counters.c19
-rw-r--r--test/profile/instrprof-set-filename.c14
-rw-r--r--test/profile/instrprof-without-libc.c60
-rw-r--r--test/profile/instrprof-write-file-atexit-explicitly.c17
-rw-r--r--test/profile/instrprof-write-file-only.c35
-rw-r--r--test/profile/instrprof-write-file.c34
-rw-r--r--test/profile/lit.cfg53
-rw-r--r--test/profile/lit.site.cfg.in11
-rw-r--r--test/sanitizer_common/CMakeLists.txt46
-rw-r--r--test/sanitizer_common/TestCases/Linux/aligned_alloc.c8
-rw-r--r--test/sanitizer_common/TestCases/Linux/clock_gettime.c11
-rw-r--r--test/sanitizer_common/TestCases/Linux/getpass.cc32
-rw-r--r--test/sanitizer_common/TestCases/Linux/getpwnam_r_invalid_user.cc19
-rw-r--r--test/sanitizer_common/TestCases/Linux/lit.local.cfg9
-rw-r--r--test/sanitizer_common/TestCases/Linux/mlock_test.cc13
-rw-r--r--test/sanitizer_common/TestCases/Linux/open_memstream.cc57
-rw-r--r--test/sanitizer_common/TestCases/Linux/ptrace.cc60
-rw-r--r--test/sanitizer_common/TestCases/Linux/timerfd.cc52
-rw-r--r--test/sanitizer_common/TestCases/corelimit.cc16
-rw-r--r--test/sanitizer_common/TestCases/malloc_hook.cc38
-rw-r--r--test/sanitizer_common/TestCases/print-stack-trace.cc24
-rw-r--r--test/sanitizer_common/TestCases/pthread_mutexattr_get.cc19
-rw-r--r--test/sanitizer_common/Unit/lit.site.cfg.in15
-rw-r--r--test/sanitizer_common/lit.common.cfg38
-rw-r--r--test/sanitizer_common/lit.site.cfg.in9
-rw-r--r--test/tsan/CMakeLists.txt27
-rw-r--r--test/tsan/Linux/lit.local.cfg9
-rw-r--r--test/tsan/Linux/mutex_robust.cc36
-rw-r--r--test/tsan/Linux/mutex_robust2.cc41
-rw-r--r--test/tsan/Linux/user_fopen.cc34
-rw-r--r--test/tsan/Linux/user_malloc.cc27
-rw-r--r--test/tsan/Unit/lit.site.cfg.in14
-rw-r--r--test/tsan/aligned_vs_unaligned_race.cc34
-rw-r--r--test/tsan/allocator_returns_null.cc64
-rw-r--r--test/tsan/atexit.cc29
-rw-r--r--test/tsan/atexit2.cc26
-rw-r--r--test/tsan/atomic_free.cc19
-rw-r--r--test/tsan/atomic_free2.cc19
-rw-r--r--test/tsan/atomic_norace.cc61
-rw-r--r--test/tsan/atomic_race.cc80
-rw-r--r--test/tsan/atomic_stack.cc29
-rw-r--r--test/tsan/barrier.cc37
-rw-r--r--test/tsan/bench.h59
-rw-r--r--test/tsan/bench_acquire_only.cc19
-rw-r--r--test/tsan/bench_acquire_release.cc18
-rw-r--r--test/tsan/bench_local_mutex.cc27
-rw-r--r--test/tsan/bench_mutex.cc28
-rw-r--r--test/tsan/bench_release_only.cc23
-rw-r--r--test/tsan/bench_rwmutex.cc25
-rw-r--r--test/tsan/bench_shadow_flush.cc48
-rw-r--r--test/tsan/bench_single_writer.cc23
-rw-r--r--test/tsan/bench_ten_mutexes.cc26
-rw-r--r--test/tsan/benign_race.cc39
-rw-r--r--test/tsan/blacklist.cc30
-rw-r--r--test/tsan/blacklist2.cc49
-rw-r--r--test/tsan/cond.c53
-rw-r--r--test/tsan/cond_cancel.c37
-rw-r--r--test/tsan/cond_race.cc40
-rw-r--r--test/tsan/cond_version.c44
-rw-r--r--test/tsan/deadlock_detector_stress_test.cc596
-rw-r--r--test/tsan/deep_stack1.cc44
-rw-r--r--test/tsan/default_options.cc32
-rwxr-xr-xtest/tsan/deflake.bash17
-rw-r--r--test/tsan/dlclose.cc58
-rw-r--r--test/tsan/fd_close_norace.cc33
-rw-r--r--test/tsan/fd_close_norace2.cc30
-rw-r--r--test/tsan/fd_dup_norace.cc34
-rw-r--r--test/tsan/fd_location.cc33
-rw-r--r--test/tsan/fd_pipe_norace.cc33
-rw-r--r--test/tsan/fd_pipe_race.cc37
-rw-r--r--test/tsan/fd_socket_connect_norace.cc45
-rw-r--r--test/tsan/fd_socket_norace.cc52
-rw-r--r--test/tsan/fd_socketpair_norace.cc37
-rw-r--r--test/tsan/fd_stdout_race.cc41
-rw-r--r--test/tsan/fork_atexit.cc37
-rw-r--r--test/tsan/fork_deadlock.cc48
-rw-r--r--test/tsan/fork_multithreaded.cc42
-rw-r--r--test/tsan/fork_multithreaded3.cc40
-rw-r--r--test/tsan/free_race.c49
-rw-r--r--test/tsan/free_race.c.supp2
-rw-r--r--test/tsan/free_race2.c26
-rw-r--r--test/tsan/getline_nohang.cc39
-rw-r--r--test/tsan/global_race.cc28
-rw-r--r--test/tsan/global_race2.cc28
-rw-r--r--test/tsan/global_race3.cc32
-rw-r--r--test/tsan/halt_on_error.cc27
-rw-r--r--test/tsan/heap_race.cc20
-rw-r--r--test/tsan/ignore_free.cc35
-rw-r--r--test/tsan/ignore_lib0.cc30
-rw-r--r--test/tsan/ignore_lib0.cc.supp2
-rw-r--r--test/tsan/ignore_lib1.cc42
-rw-r--r--test/tsan/ignore_lib1.cc.supp2
-rw-r--r--test/tsan/ignore_lib2.cc33
-rw-r--r--test/tsan/ignore_lib2.cc.supp2
-rw-r--r--test/tsan/ignore_lib3.cc33
-rw-r--r--test/tsan/ignore_lib3.cc.supp2
-rw-r--r--test/tsan/ignore_lib_lib.h25
-rw-r--r--test/tsan/ignore_malloc.cc38
-rw-r--r--test/tsan/ignore_race.cc31
-rw-r--r--test/tsan/ignore_sync.cc30
-rw-r--r--test/tsan/inlined_memcpy_race.cc38
-rw-r--r--test/tsan/inlined_memcpy_race2.cc38
-rw-r--r--test/tsan/interface_atomic_test.c16
-rw-r--r--test/tsan/java.h21
-rw-r--r--test/tsan/java_alloc.cc38
-rw-r--r--test/tsan/java_finalizer.cc27
-rw-r--r--test/tsan/java_lock.cc36
-rw-r--r--test/tsan/java_lock_move.cc41
-rw-r--r--test/tsan/java_lock_rec.cc55
-rw-r--r--test/tsan/java_lock_rec_race.cc49
-rw-r--r--test/tsan/java_move_overlap.cc72
-rw-r--r--test/tsan/java_move_overlap_race.cc53
-rw-r--r--test/tsan/java_race.cc25
-rw-r--r--test/tsan/java_race_move.cc33
-rw-r--r--test/tsan/java_rwlock.cc36
-rw-r--r--test/tsan/libcxx/lit.local.cfg10
-rw-r--r--test/tsan/libcxx/std_shared_ptr.cc24
-rw-r--r--test/tsan/lit.cfg65
-rw-r--r--test/tsan/lit.site.cfg.in10
-rw-r--r--test/tsan/load_shared_lib.cc66
-rw-r--r--test/tsan/longjmp.cc22
-rw-r--r--test/tsan/longjmp2.cc24
-rw-r--r--test/tsan/longjmp3.cc48
-rw-r--r--test/tsan/longjmp4.cc51
-rw-r--r--test/tsan/malloc_overflow.cc23
-rw-r--r--test/tsan/malloc_stack.cc25
-rw-r--r--test/tsan/map32bit.cc41
-rw-r--r--test/tsan/memcpy_race.cc42
-rw-r--r--test/tsan/mmap_large.cc20
-rw-r--r--test/tsan/mop_with_offset.cc36
-rw-r--r--test/tsan/mop_with_offset2.cc36
-rw-r--r--test/tsan/must_deadlock.cc50
-rw-r--r--test/tsan/mutex_bad_read_lock.cc19
-rw-r--r--test/tsan/mutex_bad_read_unlock.cc20
-rw-r--r--test/tsan/mutex_bad_unlock.cc18
-rw-r--r--test/tsan/mutex_cycle2.c35
-rw-r--r--test/tsan/mutex_destroy_locked.cc22
-rw-r--r--test/tsan/mutex_double_lock.cc29
-rw-r--r--test/tsan/mutexset1.cc37
-rw-r--r--test/tsan/mutexset2.cc37
-rw-r--r--test/tsan/mutexset3.cc45
-rw-r--r--test/tsan/mutexset4.cc45
-rw-r--r--test/tsan/mutexset5.cc46
-rw-r--r--test/tsan/mutexset6.cc53
-rw-r--r--test/tsan/mutexset7.cc40
-rw-r--r--test/tsan/mutexset8.cc39
-rw-r--r--test/tsan/printf-1.c16
-rw-r--r--test/tsan/process_sleep.h7
-rw-r--r--test/tsan/pthread_atfork_deadlock.c33
-rw-r--r--test/tsan/race_on_barrier.c31
-rw-r--r--test/tsan/race_on_barrier2.c31
-rw-r--r--test/tsan/race_on_heap.cc47
-rw-r--r--test/tsan/race_on_mutex.c42
-rw-r--r--test/tsan/race_on_mutex2.c24
-rw-r--r--test/tsan/race_on_puts.cc29
-rw-r--r--test/tsan/race_on_read.cc41
-rw-r--r--test/tsan/race_on_speculative_load.cc27
-rw-r--r--test/tsan/race_on_write.cc39
-rw-r--r--test/tsan/race_with_finished_thread.cc43
-rw-r--r--test/tsan/signal_errno.cc49
-rw-r--r--test/tsan/signal_longjmp.cc69
-rw-r--r--test/tsan/signal_malloc.cc26
-rw-r--r--test/tsan/signal_recursive.cc132
-rw-r--r--test/tsan/signal_sync.cc58
-rw-r--r--test/tsan/signal_write.cc27
-rw-r--r--test/tsan/sigsuspend.cc44
-rw-r--r--test/tsan/simple_race.c29
-rw-r--r--test/tsan/simple_race.cc29
-rw-r--r--test/tsan/simple_stack.c66
-rw-r--r--test/tsan/simple_stack2.cc53
-rw-r--r--test/tsan/sleep_sync.cc30
-rw-r--r--test/tsan/sleep_sync2.cc22
-rw-r--r--test/tsan/stack_race.cc22
-rw-r--r--test/tsan/stack_race2.cc29
-rw-r--r--test/tsan/static_init1.cc27
-rw-r--r--test/tsan/static_init2.cc33
-rw-r--r--test/tsan/static_init3.cc47
-rw-r--r--test/tsan/static_init4.cc37
-rw-r--r--test/tsan/static_init5.cc42
-rw-r--r--test/tsan/static_init6.cc42
-rw-r--r--test/tsan/sunrpc.cc25
-rw-r--r--test/tsan/suppress_same_address.cc29
-rw-r--r--test/tsan/suppress_same_stacks.cc27
-rw-r--r--test/tsan/suppressions_global.cc29
-rw-r--r--test/tsan/suppressions_global.cc.supp2
-rw-r--r--test/tsan/suppressions_race.cc31
-rw-r--r--test/tsan/suppressions_race.cc.supp2
-rw-r--r--test/tsan/suppressions_race2.cc31
-rw-r--r--test/tsan/suppressions_race2.cc.supp2
-rwxr-xr-xtest/tsan/test_output.sh66
-rw-r--r--test/tsan/thread_detach.c20
-rw-r--r--test/tsan/thread_end_with_ignore.cc24
-rw-r--r--test/tsan/thread_end_with_ignore2.cc12
-rw-r--r--test/tsan/thread_end_with_ignore3.cc22
-rw-r--r--test/tsan/thread_leak.c17
-rw-r--r--test/tsan/thread_leak2.c17
-rw-r--r--test/tsan/thread_leak3.c17
-rw-r--r--test/tsan/thread_leak4.c18
-rw-r--r--test/tsan/thread_leak5.c20
-rw-r--r--test/tsan/thread_name.cc47
-rw-r--r--test/tsan/thread_name2.cc36
-rw-r--r--test/tsan/tiny_race.c21
-rw-r--r--test/tsan/tls_race.cc21
-rw-r--r--test/tsan/tls_race2.cc29
-rw-r--r--test/tsan/tsan-vs-gvn.cc38
-rw-r--r--test/tsan/unaligned_norace.cc84
-rw-r--r--test/tsan/unaligned_race.cc139
-rw-r--r--test/tsan/vfork.cc51
-rw-r--r--test/tsan/virtual_inheritance_compile_bug.cc15
-rw-r--r--test/tsan/vptr_benign_race.cc51
-rw-r--r--test/tsan/vptr_harmful_race.cc51
-rw-r--r--test/tsan/vptr_harmful_race2.cc51
-rw-r--r--test/tsan/vptr_harmful_race3.cc53
-rw-r--r--test/tsan/vptr_harmful_race4.cc34
-rw-r--r--test/tsan/write_in_reader_lock.cc35
-rw-r--r--test/ubsan/CMakeLists.txt25
-rw-r--r--test/ubsan/TestCases/Float/cast-overflow.cpp134
-rw-r--r--test/ubsan/TestCases/Integer/add-overflow.cpp32
-rw-r--r--test/ubsan/TestCases/Integer/div-overflow.cpp10
-rw-r--r--test/ubsan/TestCases/Integer/div-zero.cpp15
-rw-r--r--test/ubsan/TestCases/Integer/incdec-overflow.cpp16
-rw-r--r--test/ubsan/TestCases/Integer/mul-overflow.cpp14
-rw-r--r--test/ubsan/TestCases/Integer/negate-overflow.cpp12
-rw-r--r--test/ubsan/TestCases/Integer/no-recover.cpp22
-rw-r--r--test/ubsan/TestCases/Integer/shift.cpp37
-rw-r--r--test/ubsan/TestCases/Integer/sub-overflow.cpp31
-rw-r--r--test/ubsan/TestCases/Integer/summary.cpp10
-rw-r--r--test/ubsan/TestCases/Integer/uadd-overflow.cpp32
-rw-r--r--test/ubsan/TestCases/Integer/uincdec-overflow.cpp16
-rw-r--r--test/ubsan/TestCases/Integer/umul-overflow.cpp19
-rw-r--r--test/ubsan/TestCases/Integer/usub-overflow.cpp31
-rw-r--r--test/ubsan/TestCases/Misc/bool.cpp10
-rw-r--r--test/ubsan/TestCases/Misc/bounds.cpp15
-rw-r--r--test/ubsan/TestCases/Misc/deduplication.cpp25
-rw-r--r--test/ubsan/TestCases/Misc/enum.cpp17
-rw-r--r--test/ubsan/TestCases/Misc/missing_return.cpp17
-rw-r--r--test/ubsan/TestCases/Misc/nonnull-arg.cpp58
-rw-r--r--test/ubsan/TestCases/Misc/nonnull.cpp15
-rw-r--r--test/ubsan/TestCases/Misc/unreachable.cpp6
-rw-r--r--test/ubsan/TestCases/Misc/vla.c11
-rw-r--r--test/ubsan/TestCases/TypeCheck/Function/function.cpp24
-rw-r--r--test/ubsan/TestCases/TypeCheck/Function/lit.local.cfg3
-rw-r--r--test/ubsan/TestCases/TypeCheck/misaligned.cpp105
-rw-r--r--test/ubsan/TestCases/TypeCheck/null.cpp38
-rw-r--r--test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp19
-rw-r--r--test/ubsan/TestCases/TypeCheck/vptr.cpp166
-rw-r--r--test/ubsan/lit.common.cfg56
-rw-r--r--test/ubsan/lit.site.cfg.in8
945 files changed, 28902 insertions, 104 deletions
diff --git a/test/BlocksRuntime/block-static.c b/test/BlocksRuntime/block-static.c
new file mode 100644
index 000000000000..d38c816cf015
--- /dev/null
+++ b/test/BlocksRuntime/block-static.c
@@ -0,0 +1,25 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+// testfilerunner CONFIG
+
+#include <stdio.h>
+
+
+int main(int argc, char **argv) {
+ static int numberOfSquesals = 5;
+
+ ^{ numberOfSquesals = 6; }();
+
+ if (numberOfSquesals == 6) {
+ printf("%s: success\n", argv[0]);
+ return 0;
+ }
+ printf("**** did not update static local, rdar://6177162\n");
+ return 1;
+
+}
+
diff --git a/test/BlocksRuntime/blockimport.c b/test/BlocksRuntime/blockimport.c
new file mode 100644
index 000000000000..178fce4395e5
--- /dev/null
+++ b/test/BlocksRuntime/blockimport.c
@@ -0,0 +1,51 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+/*
+ * blockimport.c
+ * testObjects
+ *
+ * Created by Blaine Garst on 10/13/08.
+ *
+ */
+
+
+//
+// pure C nothing more needed
+// CONFIG rdar://6289344
+
+#include <stdio.h>
+#include <Block.h>
+#include <Block_private.h>
+
+
+
+
+int main(int argc, char *argv[]) {
+ int i = 1;
+ int (^intblock)(void) = ^{ return i*10; };
+
+ void (^vv)(void) = ^{
+ if (argc > 0) {
+ printf("intblock returns %d\n", intblock());
+ }
+ };
+
+#if 0
+ //printf("Block dump %s\n", _Block_dump(vv));
+ {
+ struct Block_layout *layout = (struct Block_layout *)(void *)vv;
+ printf("isa %p\n", layout->isa);
+ printf("flags %x\n", layout->flags);
+ printf("descriptor %p\n", layout->descriptor);
+ printf("descriptor->size %d\n", layout->descriptor->size);
+ }
+#endif
+ void (^vvcopy)(void) = Block_copy(vv);
+ Block_release(vvcopy);
+ printf("%s: success\n", argv[0]);
+ return 0;
+}
diff --git a/test/BlocksRuntime/byrefaccess.c b/test/BlocksRuntime/byrefaccess.c
new file mode 100644
index 000000000000..4565553338ac
--- /dev/null
+++ b/test/BlocksRuntime/byrefaccess.c
@@ -0,0 +1,34 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+//
+// byrefaccess.m
+// test that byref access to locals is accurate
+// testObjects
+//
+// Created by Blaine Garst on 5/13/08.
+//
+// CONFIG
+
+#include <stdio.h>
+
+
+void callVoidVoid(void (^closure)(void)) {
+ closure();
+}
+
+int main(int argc, char *argv[]) {
+ __block int i = 10;
+
+ callVoidVoid(^{ ++i; });
+
+ if (i != 11) {
+ printf("*** %s didn't update i\n", argv[0]);
+ return 1;
+ }
+ printf("%s: success\n", argv[0]);
+ return 0;
+}
diff --git a/test/BlocksRuntime/byrefcopy.c b/test/BlocksRuntime/byrefcopy.c
new file mode 100644
index 000000000000..513b63c2725d
--- /dev/null
+++ b/test/BlocksRuntime/byrefcopy.c
@@ -0,0 +1,41 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+//
+// byrefcopy.m
+// testObjects
+//
+// Created by Blaine Garst on 5/13/08.
+//
+
+#include <stdio.h>
+#include <Block.h>
+#include <Block_private.h>
+
+// CONFIG
+
+void callVoidVoid(void (^closure)(void)) {
+ closure();
+}
+
+int main(int argc, char *argv[]) {
+ int __block i = 10;
+
+ void (^block)(void) = ^{ ++i; };
+ //printf("original (old style) is %s\n", _Block_dump_old(block));
+ //printf("original (new style) is %s\n", _Block_dump(block));
+ void (^blockcopy)(void) = Block_copy(block);
+ //printf("copy is %s\n", _Block_dump(blockcopy));
+ // use a copy & see that it updates i
+ callVoidVoid(block);
+
+ if (i != 11) {
+ printf("*** %s didn't update i\n", argv[0]);
+ return 1;
+ }
+ printf("%s: success\n", argv[0]);
+ return 0;
+}
diff --git a/test/BlocksRuntime/byrefcopycopy.c b/test/BlocksRuntime/byrefcopycopy.c
new file mode 100644
index 000000000000..d6fafc152e1d
--- /dev/null
+++ b/test/BlocksRuntime/byrefcopycopy.c
@@ -0,0 +1,46 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+// CONFIG rdar://6255170
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <Block.h>
+#include <Block_private.h>
+#include <assert.h>
+
+
+int
+main(int argc, char *argv[])
+{
+ __block int var = 0;
+ int shouldbe = 0;
+ void (^b)(void) = ^{ var++; /*printf("var is at %p with value %d\n", &var, var);*/ };
+ __typeof(b) _b;
+ //printf("before copy...\n");
+ b(); ++shouldbe;
+ size_t i;
+
+ for (i = 0; i < 10; i++) {
+ _b = Block_copy(b); // make a new copy each time
+ assert(_b);
+ ++shouldbe;
+ _b(); // should still update the stack
+ Block_release(_b);
+ }
+
+ //printf("after...\n");
+ b(); ++shouldbe;
+
+ if (var != shouldbe) {
+ printf("Hmm, var is %d but should be %d\n", var, shouldbe);
+ return 1;
+ }
+ printf("%s: Success!!\n", argv[0]);
+
+ return 0;
+}
diff --git a/test/BlocksRuntime/byrefcopyinner.c b/test/BlocksRuntime/byrefcopyinner.c
new file mode 100644
index 000000000000..07770933afe3
--- /dev/null
+++ b/test/BlocksRuntime/byrefcopyinner.c
@@ -0,0 +1,32 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+#include <Block.h>
+#include <stdio.h>
+
+// CONFIG rdar://6225809
+// fixed in 5623
+
+int main(int argc, char *argv[]) {
+ __block int a = 42;
+ int* ap = &a; // just to keep the address on the stack.
+
+ void (^b)(void) = ^{
+ //a; // workaround, a should be implicitly imported
+ Block_copy(^{
+ a = 2;
+ });
+ };
+
+ Block_copy(b);
+
+ if(&a == ap) {
+ printf("**** __block heap storage should have been created at this point\n");
+ return 1;
+ }
+ printf("%s: Success\n", argv[0]);
+ return 0;
+}
diff --git a/test/BlocksRuntime/byrefcopyint.c b/test/BlocksRuntime/byrefcopyint.c
new file mode 100644
index 000000000000..d632f88a0bc5
--- /dev/null
+++ b/test/BlocksRuntime/byrefcopyint.c
@@ -0,0 +1,69 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+/*
+ * byrefcopyint.c
+ * testObjects
+ *
+ * Created by Blaine Garst on 12/1/08.
+ *
+ */
+
+//
+// byrefcopyid.m
+// testObjects
+//
+// Created by Blaine Garst on 5/13/08.
+//
+
+// Tests copying of blocks with byref ints
+// CONFIG rdar://6414583 -C99
+
+#include <stdio.h>
+#include <string.h>
+#include <Block.h>
+#include <Block_private.h>
+
+
+
+
+typedef void (^voidVoid)(void);
+
+voidVoid dummy;
+
+void callVoidVoid(voidVoid closure) {
+ closure();
+}
+
+
+voidVoid testRoutine(const char *whoami) {
+ __block int dumbo = strlen(whoami);
+ dummy = ^{
+ //printf("incring dumbo from %d\n", dumbo);
+ ++dumbo;
+ };
+
+
+ voidVoid copy = Block_copy(dummy);
+
+
+ return copy;
+}
+
+int main(int argc, char *argv[]) {
+ voidVoid array[100];
+ for (int i = 0; i < 100; ++i) {
+ array[i] = testRoutine(argv[0]);
+ array[i]();
+ }
+ for (int i = 0; i < 100; ++i) {
+ Block_release(array[i]);
+ }
+
+
+ printf("%s: success\n", argv[0]);
+ return 0;
+}
diff --git a/test/BlocksRuntime/byrefcopystack.c b/test/BlocksRuntime/byrefcopystack.c
new file mode 100644
index 000000000000..d119afa3668f
--- /dev/null
+++ b/test/BlocksRuntime/byrefcopystack.c
@@ -0,0 +1,41 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+//
+// byrefcopystack.m
+// testObjects
+//
+// Created by Blaine Garst on 5/13/08.
+//
+
+
+
+#include <stdio.h>
+#include <Block.h>
+
+// CONFIG rdar://6255170
+
+void (^bumpi)(void);
+int (^geti)(void);
+
+void setClosures() {
+ int __block i = 10;
+ bumpi = Block_copy(^{ ++i; });
+ geti = Block_copy(^{ return i; });
+}
+
+int main(int argc, char *argv[]) {
+ setClosures();
+ bumpi();
+ int i = geti();
+
+ if (i != 11) {
+ printf("*** %s didn't update i\n", argv[0]);
+ return 1;
+ }
+ printf("%s: success\n", argv[0]);
+ return 0;
+}
diff --git a/test/BlocksRuntime/byrefsanity.c b/test/BlocksRuntime/byrefsanity.c
new file mode 100644
index 000000000000..dfa16b0ddd6a
--- /dev/null
+++ b/test/BlocksRuntime/byrefsanity.c
@@ -0,0 +1,73 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+// CONFIG
+
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <Block.h>
+
+int
+main(int argc, char *argv[])
+{
+ __block int var = 0;
+ void (^b)(void) = ^{ var++; };
+
+ //sanity(b);
+ b();
+ printf("%s: success!\n", argv[0]);
+ return 0;
+}
+
+
+#if 1
+/* replicated internal data structures: BEWARE, MAY CHANGE!!! */
+
+enum {
+ BLOCK_REFCOUNT_MASK = (0xffff),
+ BLOCK_NEEDS_FREE = (1 << 24),
+ BLOCK_HAS_COPY_DISPOSE = (1 << 25),
+ BLOCK_NO_COPY = (1 << 26), // interim byref: no copies allowed
+ BLOCK_IS_GC = (1 << 27),
+ BLOCK_IS_GLOBAL = (1 << 28),
+};
+
+struct byref_id {
+ struct byref_id *forwarding;
+ int flags;//refcount;
+ int size;
+ void (*byref_keep)(struct byref_id *dst, struct byref_id *src);
+ void (*byref_destroy)(struct byref_id *);
+ int var;
+};
+struct Block_basic2 {
+ void *isa;
+ int Block_flags; // int32_t
+ int Block_size; // XXX should be packed into Block_flags
+ void (*Block_invoke)(void *);
+ void (*Block_copy)(void *dst, void *src);
+ void (*Block_dispose)(void *);
+ struct byref_id *ref;
+};
+
+void sanity(void *arg) {
+ struct Block_basic2 *bb = (struct Block_basic2 *)arg;
+ if ( ! (bb->Block_flags & BLOCK_HAS_COPY_DISPOSE)) {
+ printf("missing copy/dispose helpers for byref data\n");
+ exit(1);
+ }
+ struct byref_id *ref = bb->ref;
+ if (ref->forwarding != ref) {
+ printf("forwarding pointer should be %p but is %p\n", ref, ref->forwarding);
+ exit(1);
+ }
+}
+#endif
+
+
+
diff --git a/test/BlocksRuntime/byrefstruct.c b/test/BlocksRuntime/byrefstruct.c
new file mode 100644
index 000000000000..a3dc44e2c36e
--- /dev/null
+++ b/test/BlocksRuntime/byrefstruct.c
@@ -0,0 +1,57 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+// -*- mode:C; c-basic-offset:4; tab-width:4; intent-tabs-mode:nil; -*-
+// CONFIG
+
+#import <stdio.h>
+#import <stdlib.h>
+#import <string.h>
+
+typedef struct {
+ unsigned long ps[30];
+ int qs[30];
+} BobTheStruct;
+
+int main (int argc, const char * argv[]) {
+ __block BobTheStruct fiddly;
+ BobTheStruct copy;
+
+ void (^incrementFiddly)() = ^{
+ int i;
+ for(i=0; i<30; i++) {
+ fiddly.ps[i]++;
+ fiddly.qs[i]++;
+ }
+ };
+
+ memset(&fiddly, 0xA5, sizeof(fiddly));
+ memset(&copy, 0x2A, sizeof(copy));
+
+ int i;
+ for(i=0; i<30; i++) {
+ fiddly.ps[i] = i * i * i;
+ fiddly.qs[i] = -i * i * i;
+ }
+
+ copy = fiddly;
+ incrementFiddly();
+
+ if ( &copy == &fiddly ) {
+ printf("%s: struct wasn't copied.", argv[0]);
+ exit(1);
+ }
+ for(i=0; i<30; i++) {
+ //printf("[%d]: fiddly.ps: %lu, copy.ps: %lu, fiddly.qs: %d, copy.qs: %d\n", i, fiddly.ps[i], copy.ps[i], fiddly.qs[i], copy.qs[i]);
+ if ( (fiddly.ps[i] != copy.ps[i] + 1) || (fiddly.qs[i] != copy.qs[i] + 1) ) {
+ printf("%s: struct contents were not incremented.", argv[0]);
+ exit(1);
+ }
+ }
+
+ printf("%s: success\n", argv[0]);
+ return 0;
+}
diff --git a/test/BlocksRuntime/c99.c b/test/BlocksRuntime/c99.c
new file mode 100644
index 000000000000..8f31ab3fdfb8
--- /dev/null
+++ b/test/BlocksRuntime/c99.c
@@ -0,0 +1,20 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+//
+// c99.m
+//
+// CONFIG C99 rdar://problem/6399225
+
+#import <stdio.h>
+#import <stdlib.h>
+
+int main(int argc, char *argv[]) {
+ void (^blockA)(void) = ^ { ; };
+ blockA();
+ printf("%s: success\n", argv[0]);
+ exit(0);
+}
diff --git a/test/BlocksRuntime/cast.c b/test/BlocksRuntime/cast.c
new file mode 100644
index 000000000000..5bef2c19def5
--- /dev/null
+++ b/test/BlocksRuntime/cast.c
@@ -0,0 +1,37 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+/*
+ * cast.c
+ * testObjects
+ *
+ * Created by Blaine Garst on 2/17/09.
+ *
+ */
+
+// PURPOSE should allow casting of a Block reference to an arbitrary pointer and back
+// CONFIG open
+
+#include <stdio.h>
+
+
+
+int main(int argc, char *argv[]) {
+
+ void (^aBlock)(void);
+ int *ip;
+ char *cp;
+ double *dp;
+
+ ip = (int *)aBlock;
+ cp = (char *)aBlock;
+ dp = (double *)aBlock;
+ aBlock = (void (^)(void))ip;
+ aBlock = (void (^)(void))cp;
+ aBlock = (void (^)(void))dp;
+ printf("%s: success", argv[0]);
+ return 0;
+}
diff --git a/test/BlocksRuntime/constassign.c b/test/BlocksRuntime/constassign.c
new file mode 100644
index 000000000000..537cb2df0597
--- /dev/null
+++ b/test/BlocksRuntime/constassign.c
@@ -0,0 +1,28 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+//
+// constassign.c
+// bocktest
+//
+// Created by Blaine Garst on 3/21/08.
+//
+// shouldn't be able to assign to a const pointer
+// CONFIG error: assignment of read-only
+
+#import <stdio.h>
+
+void foo(void) { printf("I'm in foo\n"); }
+void bar(void) { printf("I'm in bar\n"); }
+
+int main(int argc, char *argv[]) {
+ void (*const fptr)(void) = foo;
+ void (^const blockA)(void) = ^ { printf("hello\n"); };
+ blockA = ^ { printf("world\n"); } ;
+ fptr = bar;
+ printf("%s: success\n", argv[0]);
+ return 0;
+}
diff --git a/test/BlocksRuntime/copy-block-literal-rdar6439600.c b/test/BlocksRuntime/copy-block-literal-rdar6439600.c
new file mode 100644
index 000000000000..6fa488eee4ff
--- /dev/null
+++ b/test/BlocksRuntime/copy-block-literal-rdar6439600.c
@@ -0,0 +1,29 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+// CONFIG open rdar://6439600
+
+#import <stdio.h>
+#import <stdlib.h>
+
+#define NUMBER_OF_BLOCKS 100
+int main (int argc, const char * argv[]) {
+ int (^x[NUMBER_OF_BLOCKS])();
+ int i;
+
+ for(i=0; i<NUMBER_OF_BLOCKS; i++) x[i] = ^{ return i; };
+
+ for(i=0; i<NUMBER_OF_BLOCKS; i++) {
+ if (x[i]() != i) {
+ printf("%s: failure, %d != %d\n", argv[0], x[i](), i);
+ exit(1);
+ }
+ }
+
+ printf("%s: success\n", argv[0]);
+
+ return 0;
+}
diff --git a/test/BlocksRuntime/copyconstructor.C b/test/BlocksRuntime/copyconstructor.C
new file mode 100644
index 000000000000..626d33e80e80
--- /dev/null
+++ b/test/BlocksRuntime/copyconstructor.C
@@ -0,0 +1,85 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+#include <stdio.h>
+#include <Block.h>
+
+// CONFIG C++ rdar://6243400,rdar://6289367
+
+
+int constructors = 0;
+int destructors = 0;
+
+
+#define CONST const
+
+class TestObject
+{
+public:
+ TestObject(CONST TestObject& inObj);
+ TestObject();
+ ~TestObject();
+
+ TestObject& operator=(CONST TestObject& inObj);
+
+ int version() CONST { return _version; }
+private:
+ mutable int _version;
+};
+
+TestObject::TestObject(CONST TestObject& inObj)
+
+{
+ ++constructors;
+ _version = inObj._version;
+ //printf("%p (%d) -- TestObject(const TestObject&) called\n", this, _version);
+}
+
+
+TestObject::TestObject()
+{
+ _version = ++constructors;
+ //printf("%p (%d) -- TestObject() called\n", this, _version);
+}
+
+
+TestObject::~TestObject()
+{
+ //printf("%p -- ~TestObject() called\n", this);
+ ++destructors;
+}
+
+
+TestObject& TestObject::operator=(CONST TestObject& inObj)
+{
+ //printf("%p -- operator= called\n", this);
+ _version = inObj._version;
+ return *this;
+}
+
+
+
+void testRoutine() {
+ TestObject one;
+
+ void (^b)(void) = ^{ printf("my const copy of one is %d\n", one.version()); };
+}
+
+
+
+int main(int argc, char *argv[]) {
+ testRoutine();
+ if (constructors == 0) {
+ printf("No copy constructors!!!\n");
+ return 1;
+ }
+ if (constructors != destructors) {
+ printf("%d constructors but only %d destructors\n", constructors, destructors);
+ return 1;
+ }
+ printf("%s:success\n", argv[0]);
+ return 0;
+}
diff --git a/test/BlocksRuntime/copynull.c b/test/BlocksRuntime/copynull.c
new file mode 100644
index 000000000000..c49e499f3ab6
--- /dev/null
+++ b/test/BlocksRuntime/copynull.c
@@ -0,0 +1,37 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+/*
+ * copynull.c
+ * testObjects
+ *
+ * Created by Blaine Garst on 10/15/08.
+ *
+ */
+
+#import <stdio.h>
+#import <Block.h>
+#import <Block_private.h>
+
+// CONFIG rdar://6295848
+
+int main(int argc, char *argv[]) {
+
+ void (^block)(void) = (void (^)(void))0;
+ void (^blockcopy)(void) = Block_copy(block);
+
+ if (blockcopy != (void (^)(void))0) {
+ printf("whoops, somehow we copied NULL!\n");
+ return 1;
+ }
+ // make sure we can also
+ Block_release(blockcopy);
+ // and more secretly
+ //_Block_destroy(blockcopy);
+
+ printf("%s: success\n", argv[0]);
+ return 0;
+}
diff --git a/test/BlocksRuntime/dispatch_async.c b/test/BlocksRuntime/dispatch_async.c
new file mode 100644
index 000000000000..e3e517c54650
--- /dev/null
+++ b/test/BlocksRuntime/dispatch_async.c
@@ -0,0 +1,57 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#include <dispatch/dispatch.h>
+#include <unistd.h>
+//#import <Foundation/Foundation.h>
+#include <Block.h>
+
+// CONFIG rdar://problem/6371811
+
+const char *whoami = "nobody";
+
+void EnqueueStuff(dispatch_queue_t q)
+{
+ __block CFIndex counter;
+
+ // above call has a side effect: it works around:
+ // <rdar://problem/6225809> __block variables not implicitly imported into intermediate scopes
+ dispatch_async(q, ^{
+ counter = 0;
+ });
+
+
+ dispatch_async(q, ^{
+ //printf("outer block.\n");
+ counter++;
+ dispatch_async(q, ^{
+ //printf("inner block.\n");
+ counter--;
+ if(counter == 0) {
+ printf("%s: success\n", whoami);
+ exit(0);
+ }
+ });
+ if(counter == 0) {
+ printf("already done? inconceivable!\n");
+ exit(1);
+ }
+ });
+}
+
+int main (int argc, const char * argv[]) {
+ dispatch_queue_t q = dispatch_queue_create("queue", NULL);
+
+ whoami = argv[0];
+
+ EnqueueStuff(q);
+
+ dispatch_main();
+ printf("shouldn't get here\n");
+ return 1;
+}
diff --git a/test/BlocksRuntime/dispatch_call_Block_with_release.c b/test/BlocksRuntime/dispatch_call_Block_with_release.c
new file mode 100644
index 000000000000..9e06f69ba762
--- /dev/null
+++ b/test/BlocksRuntime/dispatch_call_Block_with_release.c
@@ -0,0 +1,31 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+#include <stdio.h>
+#include <Block.h>
+
+// CONFIG
+
+void callsomething(const char *format, int argument) {
+}
+
+void
+dispatch_call_Block_with_release2(void *block)
+{
+ void (^b)(void) = (void (^)(void))block;
+ b();
+ Block_release(b);
+}
+
+int main(int argc, char *argv[]) {
+ void (^b1)(void) = ^{ callsomething("argc is %d\n", argc); };
+ void (^b2)(void) = ^{ callsomething("hellow world\n", 0); }; // global block now
+
+ dispatch_call_Block_with_release2(Block_copy(b1));
+ dispatch_call_Block_with_release2(Block_copy(b2));
+ printf("%s: Success\n", argv[0]);
+ return 0;
+}
diff --git a/test/BlocksRuntime/fail.c b/test/BlocksRuntime/fail.c
new file mode 100644
index 000000000000..28dbc2d1521f
--- /dev/null
+++ b/test/BlocksRuntime/fail.c
@@ -0,0 +1,107 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+/*
+ * fail.c
+ * testObjects
+ *
+ * Created by Blaine Garst on 9/16/08.
+ *
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+
+bool readfile(char *buffer, const char *from) {
+ int fd = open(from, 0);
+ if (fd < 0) return false;
+ int count = read(fd, buffer, 512);
+ if (count < 0) return false;
+ buffer[count] = 0; // zap newline
+ return true;
+}
+
+// basic idea, take compiler args, run compiler, and verify that expected failure matches any existing one
+
+int main(int argc, char *argv[]) {
+ if (argc == 1) return 0;
+ char *copy[argc+1]; // make a copy
+ // find and strip off -e "errorfile"
+ char *errorfile = NULL;
+ int counter = 0, i = 0;
+ for (i = 1; i < argc; ++i) { // skip 0 arg which is "fail"
+ if (!strncmp(argv[i], "-e", 2)) {
+ errorfile = argv[++i];
+ }
+ else {
+ copy[counter++] = argv[i];
+ }
+ }
+ copy[counter] = NULL;
+ pid_t child = fork();
+ char buffer[512];
+ if (child == 0) {
+ // in child
+ sprintf(buffer, "/tmp/errorfile_%d", getpid());
+ close(1);
+ int fd = creat(buffer, 0777);
+ if (fd != 1) {
+ fprintf(stderr, "didn't open custom error file %s as 1, got %d\n", buffer, fd);
+ exit(1);
+ }
+ close(2);
+ dup(1);
+ int result = execv(copy[0], copy);
+ exit(10);
+ }
+ if (child < 0) {
+ printf("fork failed\n");
+ exit(1);
+ }
+ int status = 0;
+ pid_t deadchild = wait(&status);
+ if (deadchild != child) {
+ printf("wait got %d instead of %d\n", deadchild, child);
+ exit(1);
+ }
+ if (WEXITSTATUS(status) == 0) {
+ printf("compiler exited normally, not good under these circumstances\n");
+ exit(1);
+ }
+ //printf("exit status of child %d was %d\n", child, WEXITSTATUS(status));
+ sprintf(buffer, "/tmp/errorfile_%d", child);
+ if (errorfile) {
+ //printf("ignoring error file: %s\n", errorfile);
+ char desired[512];
+ char got[512];
+ bool gotErrorFile = readfile(desired, errorfile);
+ bool gotOutput = readfile(got, buffer);
+ if (!gotErrorFile && gotOutput) {
+ printf("didn't read errorfile %s, it should have something from\n*****\n%s\n*****\nin it.\n",
+ errorfile, got);
+ exit(1);
+ }
+ else if (gotErrorFile && gotOutput) {
+ char *where = strstr(got, desired);
+ if (!where) {
+ printf("didn't find contents of %s in %s\n", errorfile, buffer);
+ exit(1);
+ }
+ }
+ else {
+ printf("errorfile %s and output %s inconsistent\n", errorfile, buffer);
+ exit(1);
+ }
+ }
+ unlink(buffer);
+ printf("success\n");
+ exit(0);
+}
+
diff --git a/test/BlocksRuntime/flagsisa.c b/test/BlocksRuntime/flagsisa.c
new file mode 100644
index 000000000000..5d4b2dcb4030
--- /dev/null
+++ b/test/BlocksRuntime/flagsisa.c
@@ -0,0 +1,21 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+#include <stdio.h>
+
+/* CONFIG rdar://6310599
+ */
+
+int main(int argc, char *argv[])
+{
+ __block int flags;
+ __block void *isa;
+
+ ^{ flags=1; isa = (void *)isa; };
+ printf("%s: success\n", argv[0]);
+ return 0;
+}
+
diff --git a/test/BlocksRuntime/globalexpression.c b/test/BlocksRuntime/globalexpression.c
new file mode 100644
index 000000000000..eeedd75e7078
--- /dev/null
+++ b/test/BlocksRuntime/globalexpression.c
@@ -0,0 +1,42 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+// testfilerunner CONFIG
+
+#import <stdio.h>
+#import <Block.h>
+
+int global;
+
+void (^gblock)(int) = ^(int x){ global = x; };
+
+int main(int argc, char *argv[]) {
+ gblock(1);
+ if (global != 1) {
+ printf("%s: *** did not set global to 1\n", argv[0]);
+ return 1;
+ }
+ void (^gblockcopy)(int) = Block_copy(gblock);
+ if (gblockcopy != gblock) {
+ printf("global copy %p not a no-op %p\n", (void *)gblockcopy, (void *)gblock);
+ return 1;
+ }
+ Block_release(gblockcopy);
+ gblock(3);
+ if (global != 3) {
+ printf("%s: *** did not set global to 3\n", argv[0]);
+ return 1;
+ }
+ gblockcopy = Block_copy(gblock);
+ gblockcopy(5);
+ if (global != 5) {
+ printf("%s: *** did not set global to 5\n", argv[0]);
+ return 1;
+ }
+ printf("%s: Success!\n", argv[0]);
+ return 0;
+}
+
diff --git a/test/BlocksRuntime/goto.c b/test/BlocksRuntime/goto.c
new file mode 100644
index 000000000000..7e5b08adbe8e
--- /dev/null
+++ b/test/BlocksRuntime/goto.c
@@ -0,0 +1,34 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+/*
+ * goto.c
+ * testObjects
+ *
+ * Created by Blaine Garst on 10/17/08.
+ *
+ */
+
+// CONFIG rdar://6289031
+
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+ __block int val = 0;
+
+ ^{ val = 1; }();
+
+ if (val == 0) {
+ goto out_bad; // error: local byref variable val is in the scope of this goto
+ }
+
+ printf("%s: Success!\n", argv[0]);
+ return 0;
+out_bad:
+ printf("%s: val not updated!\n", argv[0]);
+ return 1;
+}
diff --git a/test/BlocksRuntime/hasdescriptor.c b/test/BlocksRuntime/hasdescriptor.c
new file mode 100644
index 000000000000..429adb9bdb14
--- /dev/null
+++ b/test/BlocksRuntime/hasdescriptor.c
@@ -0,0 +1,29 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+
+
+// CONFIG C
+
+#include <stdio.h>
+#include <Block_private.h>
+
+
+int main(int argc, char *argv[]) {
+ void (^inner)(void) = ^ { printf("argc was %d\n", argc); };
+ void (^outer)(void) = ^{
+ inner();
+ inner();
+ };
+ //printf("size of inner is %ld\n", Block_size(inner));
+ //printf("size of outer is %ld\n", Block_size(outer));
+ if (Block_size(inner) != Block_size(outer)) {
+ printf("not the same size, using old compiler??\n");
+ return 1;
+ }
+ printf("%s: Success\n", argv[0]);
+ return 0;
+}
diff --git a/test/BlocksRuntime/josh.C b/test/BlocksRuntime/josh.C
new file mode 100644
index 000000000000..dbc7369e8c39
--- /dev/null
+++ b/test/BlocksRuntime/josh.C
@@ -0,0 +1,32 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+// CONFIG C++ GC RR open rdar://6347910
+
+
+
+struct MyStruct {
+ int something;
+};
+
+struct TestObject {
+
+ void test(void){
+ {
+ MyStruct first; // works
+ }
+ void (^b)(void) = ^{
+ MyStruct inner; // fails to compile!
+ };
+ }
+};
+
+
+
+int main(int argc, char *argv[]) {
+ printf("%s: Success\n", argv[0]);
+ return 0;
+}
diff --git a/test/BlocksRuntime/k-and-r.c b/test/BlocksRuntime/k-and-r.c
new file mode 100644
index 000000000000..16b9cc643b50
--- /dev/null
+++ b/test/BlocksRuntime/k-and-r.c
@@ -0,0 +1,33 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+// -*- mode:C; c-basic-offset:4; tab-width:4; intent-tabs-mode:nil; -*-
+// CONFIG error: incompatible block pointer types assigning
+
+#import <stdio.h>
+#import <stdlib.h>
+
+int main(int argc, char *argv[]) {
+#ifndef __cplusplus
+ char (^rot13)();
+ rot13 = ^(char c) { return (char)(((c - 'a' + 13) % 26) + 'a'); };
+ char n = rot13('a');
+ char c = rot13('p');
+ if ( n != 'n' || c != 'c' ) {
+ printf("%s: rot13('a') returned %c, rot13('p') returns %c\n", argv[0], n, c);
+ exit(1);
+ }
+#else
+// yield characteristic error message for C++
+#error incompatible block pointer types assigning
+#endif
+#ifndef __clang__
+// yield characteristic error message for C++
+#error incompatible block pointer types assigning
+#endif
+ printf("%s: success\n", argv[0]);
+ exit(0);
+}
diff --git a/test/BlocksRuntime/large-struct.c b/test/BlocksRuntime/large-struct.c
new file mode 100644
index 000000000000..1867bd02dfab
--- /dev/null
+++ b/test/BlocksRuntime/large-struct.c
@@ -0,0 +1,51 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+// -*- mode:C; c-basic-offset:4; tab-width:4; intent-tabs-mode:nil; -*-
+// CONFIG
+
+#import <stdio.h>
+#import <stdlib.h>
+#import <string.h>
+
+typedef struct {
+ unsigned long ps[30];
+ int qs[30];
+} BobTheStruct;
+
+int main (int argc, const char * argv[]) {
+ BobTheStruct inny;
+ BobTheStruct outty;
+ BobTheStruct (^copyStruct)(BobTheStruct);
+ int i;
+
+ memset(&inny, 0xA5, sizeof(inny));
+ memset(&outty, 0x2A, sizeof(outty));
+
+ for(i=0; i<30; i++) {
+ inny.ps[i] = i * i * i;
+ inny.qs[i] = -i * i * i;
+ }
+
+ copyStruct = ^(BobTheStruct aBigStruct){ return aBigStruct; }; // pass-by-value intrinsically copies the argument
+
+ outty = copyStruct(inny);
+
+ if ( &inny == &outty ) {
+ printf("%s: struct wasn't copied.", argv[0]);
+ exit(1);
+ }
+ for(i=0; i<30; i++) {
+ if ( (inny.ps[i] != outty.ps[i]) || (inny.qs[i] != outty.qs[i]) ) {
+ printf("%s: struct contents did not match.", argv[0]);
+ exit(1);
+ }
+ }
+
+ printf("%s: success\n", argv[0]);
+
+ return 0;
+}
diff --git a/test/BlocksRuntime/localisglobal.c b/test/BlocksRuntime/localisglobal.c
new file mode 100644
index 000000000000..75a79dff48ee
--- /dev/null
+++ b/test/BlocksRuntime/localisglobal.c
@@ -0,0 +1,42 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+/*
+ * localisglobal.c
+ * testObjects
+ *
+ * Created by Blaine Garst on 9/29/08.
+ *
+ * works in all configurations
+ * CONFIG rdar://6230297
+ */
+
+#include <stdio.h>
+
+void (^global)(void) = ^{ printf("hello world\n"); };
+
+int aresame(void *first, void *second) {
+ long *f = (long *)first;
+ long *s = (long *)second;
+ return *f == *s;
+}
+int main(int argc, char *argv[]) {
+ int i = 10;
+ void (^local)(void) = ^ { printf("hi %d\n", i); };
+ void (^localisglobal)(void) = ^ { printf("hi\n"); };
+
+ if (aresame(local, localisglobal)) {
+ printf("local block could be global, but isn't\n");
+ return 1;
+ }
+ if (!aresame(global, localisglobal)) {
+ printf("local block is not global, not stack, what is it??\n");
+ return 1;
+ }
+ printf("%s: success\n", argv[0]);
+ return 0;
+
+}
diff --git a/test/BlocksRuntime/macro.c b/test/BlocksRuntime/macro.c
new file mode 100644
index 000000000000..988c0689b8f8
--- /dev/null
+++ b/test/BlocksRuntime/macro.c
@@ -0,0 +1,14 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+// CONFIG open rdar://6718399
+#include <Block.h>
+
+void foo() {
+ void (^bbb)(void) = Block_copy(^ {
+ int j, cnt;
+ });
+}
diff --git a/test/BlocksRuntime/makefile b/test/BlocksRuntime/makefile
new file mode 100644
index 000000000000..2734bcae35f5
--- /dev/null
+++ b/test/BlocksRuntime/makefile
@@ -0,0 +1,70 @@
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+CCDIR=/usr/bin
+#CCDIR=/Volumes/Keep/gcc/usr/bin
+
+all: std
+
+clean:
+ rm -fr *.dSYM *.o *-bin testfilerunner
+
+TFR = ~public/bin/testfilerunner
+
+testfilerunner: testfilerunner.h testfilerunner.m
+ gcc -fobjc-gc-only -g -arch x86_64 -arch i386 -std=gnu99 testfilerunner.m -o testfilerunner -framework Foundation
+
+tests:
+ grep CONFIG *.[cmCM] | $(TFR) $(CCDIR) --
+
+open:
+ grep CONFIG *.[cmCM] | $(TFR) $(CCDIR) -open --
+
+fast:
+ grep CONFIG *.[cmCM] | $(TFR) -fast $(CCDIR) --
+
+std:
+ grep CONFIG *.[cmCM] | $(TFR) --
+
+clang:
+ grep CONFIG *.[cmCM] | $(TFR) -clang -fast --
+
+fastd:
+ grep CONFIG *.[cmCM] | $(TFR) -fast --
+
+
+# Hack Alert: arguably most of the following belongs in libclosure's Makefile; sticking it here until I get around to grokking what goes on in that file.
+sudid:
+ @echo Enabling sudo: # Hack Alert: enable sudo first thing so we don't hang at the password prompt later
+ @sudo echo Thanks
+
+
+RootsDirectory ?= /tmp/
+# Note: the libsystem project (built by the libsystemroot target below) uses the ALTUSRLOCALLIBSYSTEM variable, so we use it here to maintain parity
+ALTUSRLOCALLIBSYSTEM ?= $(RootsDirectory)/alt-usr-local-lib-system/
+altusrlocallibsystem:
+ ditto /usr/local/lib/system $(ALTUSRLOCALLIBSYSTEM) # FIXME: conditionalize this copy
+
+
+# <rdar://problem/6456031> ER: option to not require extra privileges (-nosudo or somesuch)
+Buildit ?= ~rc/bin/buildit -rootsDirectory $(RootsDirectory) -arch i386 -arch ppc -arch x86_64
+blocksroot: sudid clean altusrlocallibsystem
+ sudo $(Buildit) ..
+ ditto $(RootsDirectory)/libclosure.roots/libclosure~dst/usr/local/lib/system $(ALTUSRLOCALLIBSYSTEM)
+
+
+LibsystemVersion ?= 121
+LibsystemPath ?= ~rc/Software/SnowLeopard/Projects/Libsystem/Libsystem-$(LibsystemVersion)
+LibsystemTmpPath ?= $(RootsDirectory)/Libsystem-$(LibsystemVersion)
+libsystemroot: blocksroot
+ ditto $(LibsystemPath) $(LibsystemTmpPath) # FIXME: conditionalize this copy
+ sudo ALTUSRLOCALLIBSYSTEM=$(ALTUSRLOCALLIBSYSTEM) $(Buildit) $(LibsystemTmpPath)
+
+
+# Defaults to product of the libsystemroot target but does not automatically rebuild that, make both targets if you want a fresh root
+LibsystemRootPath ?= $(RootsDirectory)/Libsystem-$(LibsystemVersion).roots/Libsystem-$(LibsystemVersion)~dst/usr/lib/
+roottests:
+ grep CONFIG *.[cmCM] | $(TFR) -dyld $(LibsystemRootPath) -- # FIXME: figure out if I can "call" the std target instead of duplicating it
+
diff --git a/test/BlocksRuntime/modglobal.c b/test/BlocksRuntime/modglobal.c
new file mode 100644
index 000000000000..562d5a5cc418
--- /dev/null
+++ b/test/BlocksRuntime/modglobal.c
@@ -0,0 +1,18 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+#include <stdio.h>
+
+// CONFIG
+
+int AGlobal;
+
+int main(int argc, char *argv[]) {
+ void (^f)(void) = ^ { AGlobal++; };
+
+ printf("%s: success\n", argv[0]);
+ return 0;
+
+}
diff --git a/test/BlocksRuntime/nestedimport.c b/test/BlocksRuntime/nestedimport.c
new file mode 100644
index 000000000000..e8066922fbba
--- /dev/null
+++ b/test/BlocksRuntime/nestedimport.c
@@ -0,0 +1,44 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+//
+// nestedimport.m
+// testObjects
+//
+// Created by Blaine Garst on 6/24/08.
+//
+// pure C nothing more needed
+// CONFIG
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+int Global = 0;
+
+void callVoidVoid(void (^closure)(void)) {
+ closure();
+}
+
+int main(int argc, char *argv[]) {
+ int i = 1;
+
+ void (^vv)(void) = ^{
+ if (argc > 0) {
+ callVoidVoid(^{ Global = i; });
+ }
+ };
+
+ i = 2;
+ vv();
+ if (Global != 1) {
+ printf("%s: error, Global not set to captured value\n", argv[0]);
+ exit(1);
+ }
+ printf("%s: success\n", argv[0]);
+ return 0;
+}
diff --git a/test/BlocksRuntime/nullblockisa.c b/test/BlocksRuntime/nullblockisa.c
new file mode 100644
index 000000000000..ba0282e82084
--- /dev/null
+++ b/test/BlocksRuntime/nullblockisa.c
@@ -0,0 +1,43 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+//
+// nullblockisa.m
+// testObjects
+//
+// Created by Blaine Garst on 9/24/08.
+//
+// CONFIG rdar://6244520
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <Block_private.h>
+
+
+void check(void (^b)(void)) {
+ struct _custom {
+ struct Block_layout layout;
+ struct Block_byref *innerp;
+ } *custom = (struct _custom *)(void *)(b);
+ //printf("block is at %p, size is %lx, inner is %p\n", (void *)b, Block_size(b), innerp);
+ if (custom->innerp->isa != (void *)NULL) {
+ printf("not a NULL __block isa\n");
+ exit(1);
+ }
+ return;
+}
+
+int main(int argc, char *argv[]) {
+
+ __block int i;
+
+ check(^{ printf("%d\n", ++i); });
+ printf("%s: success\n", argv[0]);
+ return 0;
+}
+
diff --git a/test/BlocksRuntime/objectRRGC.c b/test/BlocksRuntime/objectRRGC.c
new file mode 100644
index 000000000000..2cefea2afd3a
--- /dev/null
+++ b/test/BlocksRuntime/objectRRGC.c
@@ -0,0 +1,77 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+/*
+ * objectRRGC.c
+ * testObjects
+ *
+ * Created by Blaine Garst on 10/31/08.
+ *
+ * Test that the runtime honors the new callouts properly for retain/release and GC
+ * CON FIG C rdar://6175959
+ */
+
+
+
+#include <stdio.h>
+#include <Block_private.h>
+
+
+int AssignCalled = 0;
+int DisposeCalled = 0;
+
+// local copy instead of libSystem.B.dylib copy
+void _Block_object_assign(void *destAddr, const void *object, const int isWeak) {
+ //printf("_Block_object_assign(%p, %p, %d) called\n", destAddr, object, isWeak);
+ AssignCalled = 1;
+}
+
+void _Block_object_dispose(const void *object, const int isWeak) {
+ //printf("_Block_object_dispose(%p, %d) called\n", object, isWeak);
+ DisposeCalled = 1;
+}
+
+struct MyStruct {
+ long isa;
+ long field;
+};
+
+typedef struct MyStruct *__attribute__((NSObject)) MyStruct_t;
+
+int main(int argc, char *argv[]) {
+ // create a block
+ struct MyStruct X;
+ MyStruct_t xp = (MyStruct_t)&X;
+ xp->field = 10;
+ void (^myBlock)(void) = ^{ printf("field is %ld\n", xp->field); };
+ // should be a copy helper generated with a calls to above routines
+ // Lets find out!
+ struct Block_layout *bl = (struct Block_layout *)(void *)myBlock;
+ if ((bl->flags & BLOCK_HAS_DESCRIPTOR) != BLOCK_HAS_DESCRIPTOR) {
+ printf("using old runtime layout!\n");
+ return 1;
+ }
+ if ((bl->flags & BLOCK_HAS_COPY_DISPOSE) != BLOCK_HAS_COPY_DISPOSE) {
+ printf("no copy dispose!!!!\n");
+ return 1;
+ }
+ // call helper routines directly. These will, in turn, we hope, call the stubs above
+ long destBuffer[256];
+ //printf("destbuffer is at %p, block at %p\n", destBuffer, (void *)bl);
+ //printf("dump is %s\n", _Block_dump(myBlock));
+ bl->descriptor->copy(destBuffer, bl);
+ bl->descriptor->dispose(bl);
+ if (AssignCalled == 0) {
+ printf("did not call assign helper!\n");
+ return 1;
+ }
+ if (DisposeCalled == 0) {
+ printf("did not call dispose helper\n");
+ return 1;
+ }
+ printf("%s: Success!\n", argv[0]);
+ return 0;
+}
diff --git a/test/BlocksRuntime/objectassign.c b/test/BlocksRuntime/objectassign.c
new file mode 100644
index 000000000000..1c4f4841419e
--- /dev/null
+++ b/test/BlocksRuntime/objectassign.c
@@ -0,0 +1,76 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+/*
+ * objectassign.c
+ * testObjects
+ *
+ * Created by Blaine Garst on 10/28/08.
+ *
+ * This just tests that the compiler is issuing the proper helper routines
+ * CONFIG C rdar://6175959
+ */
+
+
+#include <stdio.h>
+#include <Block_private.h>
+
+
+int AssignCalled = 0;
+int DisposeCalled = 0;
+
+// local copy instead of libSystem.B.dylib copy
+void _Block_object_assign(void *destAddr, const void *object, const int isWeak) {
+ //printf("_Block_object_assign(%p, %p, %d) called\n", destAddr, object, isWeak);
+ AssignCalled = 1;
+}
+
+void _Block_object_dispose(const void *object, const int isWeak) {
+ //printf("_Block_object_dispose(%p, %d) called\n", object, isWeak);
+ DisposeCalled = 1;
+}
+
+struct MyStruct {
+ long isa;
+ long field;
+};
+
+typedef struct MyStruct *__attribute__((NSObject)) MyStruct_t;
+
+int main(int argc, char *argv[]) {
+ if (__APPLE_CC__ < 5627) {
+ printf("need compiler version %d, have %d\n", 5627, __APPLE_CC__);
+ return 0;
+ }
+ // create a block
+ struct MyStruct X;
+ MyStruct_t xp = (MyStruct_t)&X;
+ xp->field = 10;
+ void (^myBlock)(void) = ^{ printf("field is %ld\n", xp->field); };
+ // should be a copy helper generated with a calls to above routines
+ // Lets find out!
+ struct Block_layout *bl = (struct Block_layout *)(void *)myBlock;
+ if ((bl->flags & BLOCK_HAS_COPY_DISPOSE) != BLOCK_HAS_COPY_DISPOSE) {
+ printf("no copy dispose!!!!\n");
+ return 1;
+ }
+ // call helper routines directly. These will, in turn, we hope, call the stubs above
+ long destBuffer[256];
+ //printf("destbuffer is at %p, block at %p\n", destBuffer, (void *)bl);
+ //printf("dump is %s\n", _Block_dump(myBlock));
+ bl->descriptor->copy(destBuffer, bl);
+ bl->descriptor->dispose(bl);
+ if (AssignCalled == 0) {
+ printf("did not call assign helper!\n");
+ return 1;
+ }
+ if (DisposeCalled == 0) {
+ printf("did not call dispose helper\n");
+ return 1;
+ }
+ printf("%s: Success!\n", argv[0]);
+ return 0;
+}
diff --git a/test/BlocksRuntime/orbars.c b/test/BlocksRuntime/orbars.c
new file mode 100644
index 000000000000..18a9244452f1
--- /dev/null
+++ b/test/BlocksRuntime/orbars.c
@@ -0,0 +1,23 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+/*
+ * orbars.c
+ * testObjects
+ *
+ * Created by Blaine Garst on 9/17/08.
+ *
+ * CONFIG rdar://6276695 error: before ‘|’ token
+ */
+
+#include <stdio.h>
+
+int main(int argc, char *argv[]) {
+ int i = 10;
+ void (^b)(void) = ^(void){ | i | printf("hello world, %d\n", ++i); };
+ printf("%s: success :-(\n", argv[0]);
+ return 0;
+}
diff --git a/test/BlocksRuntime/rdar6396238.c b/test/BlocksRuntime/rdar6396238.c
new file mode 100644
index 000000000000..280415643a1a
--- /dev/null
+++ b/test/BlocksRuntime/rdar6396238.c
@@ -0,0 +1,32 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+// CONFIG rdar://6396238
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static int count = 0;
+
+void (^mkblock(void))(void)
+{
+ count++;
+ return ^{
+ count++;
+ };
+}
+
+int main (int argc, const char * argv[]) {
+ mkblock()();
+ if (count != 2) {
+ printf("%s: failure, 2 != %d\n", argv[0], count);
+ exit(1);
+ } else {
+ printf("%s: success\n", argv[0]);
+ exit(0);
+ }
+ return 0;
+}
diff --git a/test/BlocksRuntime/rdar6405500.c b/test/BlocksRuntime/rdar6405500.c
new file mode 100644
index 000000000000..1ab4624bcfce
--- /dev/null
+++ b/test/BlocksRuntime/rdar6405500.c
@@ -0,0 +1,29 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+// CONFIG rdar://6405500
+
+#include <stdio.h>
+#include <stdlib.h>
+#import <dispatch/dispatch.h>
+#import <objc/objc-auto.h>
+
+int main (int argc, const char * argv[]) {
+ __block void (^blockFu)(size_t t);
+ blockFu = ^(size_t t){
+ if (t == 20) {
+ printf("%s: success\n", argv[0]);
+ exit(0);
+ } else
+ dispatch_async(dispatch_get_main_queue(), ^{ blockFu(20); });
+ };
+
+ dispatch_apply(10, dispatch_get_concurrent_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT), blockFu);
+
+ dispatch_main();
+ printf("shouldn't get here\n");
+ return 1;
+}
diff --git a/test/BlocksRuntime/rdar6414583.c b/test/BlocksRuntime/rdar6414583.c
new file mode 100644
index 000000000000..2ada04d3ddcc
--- /dev/null
+++ b/test/BlocksRuntime/rdar6414583.c
@@ -0,0 +1,31 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+// CONFIG rdar://6414583
+
+// a smaller case of byrefcopyint
+
+#include <Block.h>
+#include <dispatch/dispatch.h>
+#include <stdio.h>
+
+int main(int argc, char *argv[]) {
+ __block int c = 1;
+
+ //printf("&c = %p - c = %i\n", &c, c);
+
+ int i;
+ for(i =0; i < 2; i++) {
+ dispatch_block_t block = Block_copy(^{ c = i; });
+
+ block();
+// printf("%i: &c = %p - c = %i\n", i, &c, c);
+
+ Block_release(block);
+ }
+ printf("%s: success\n", argv[0]);
+ return 0;
+}
diff --git a/test/BlocksRuntime/recursive-block.c b/test/BlocksRuntime/recursive-block.c
new file mode 100644
index 000000000000..454ad48267df
--- /dev/null
+++ b/test/BlocksRuntime/recursive-block.c
@@ -0,0 +1,55 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+#include <stdio.h>
+#include <Block.h>
+#include <Block_private.h>
+#include <stdlib.h>
+
+// CONFIG
+
+
+int cumulation = 0;
+
+int doSomething(int i) {
+ cumulation += i;
+ return cumulation;
+}
+
+void dirtyStack() {
+ int i = random();
+ int j = doSomething(i);
+ int k = doSomething(j);
+ doSomething(i + j + k);
+}
+
+typedef void (^voidVoid)(void);
+
+voidVoid testFunction() {
+ int i = random();
+ __block voidVoid inner = ^{ doSomething(i); };
+ //printf("inner, on stack, is %p\n", (void*)inner);
+ /*__block*/ voidVoid outer = ^{
+ //printf("will call inner block %p\n", (void *)inner);
+ inner();
+ };
+ //printf("outer looks like: %s\n", _Block_dump(outer));
+ voidVoid result = Block_copy(outer);
+ //Block_release(inner);
+ return result;
+}
+
+
+int main(int argc, char **argv) {
+ voidVoid block = testFunction();
+ dirtyStack();
+ block();
+ Block_release(block);
+
+ printf("%s: success\n", argv[0]);
+
+ return 0;
+}
diff --git a/test/BlocksRuntime/recursive-test.c b/test/BlocksRuntime/recursive-test.c
new file mode 100644
index 000000000000..f79914863121
--- /dev/null
+++ b/test/BlocksRuntime/recursive-test.c
@@ -0,0 +1,74 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+// CONFIG open rdar://6416474
+// was rdar://5847976
+// was rdar://6348320
+
+#include <stdio.h>
+#include <Block.h>
+
+int verbose = 0;
+
+int main(int argc, char* argv[]) {
+
+ if (argc > 1) verbose = 1;
+
+ __block void (^recursive_local_block)(int);
+
+ if (verbose) printf("recursive_local_block is a local recursive block\n");
+ recursive_local_block = ^(int i) {
+ if (verbose) printf("%d\n", i);
+ if (i > 0) {
+ recursive_local_block(i - 1);
+ }
+ };
+
+ if (verbose) printf("recursive_local_block's address is %p, running it:\n", (void*)recursive_local_block);
+ recursive_local_block(5);
+
+ if (verbose) printf("Creating other_local_block: a local block that calls recursive_local_block\n");
+
+ void (^other_local_block)(int) = ^(int i) {
+ if (verbose) printf("other_local_block running\n");
+ recursive_local_block(i);
+ };
+
+ if (verbose) printf("other_local_block's address is %p, running it:\n", (void*)other_local_block);
+
+ other_local_block(5);
+
+#if __APPLE_CC__ >= 5627
+ if (verbose) printf("Creating other_copied_block: a Block_copy of a block that will call recursive_local_block\n");
+
+ void (^other_copied_block)(int) = Block_copy(^(int i) {
+ if (verbose) printf("other_copied_block running\n");
+ recursive_local_block(i);
+ });
+
+ if (verbose) printf("other_copied_block's address is %p, running it:\n", (void*)other_copied_block);
+
+ other_copied_block(5);
+#endif
+
+ __block void (^recursive_copy_block)(int);
+
+ if (verbose) printf("Creating recursive_copy_block: a Block_copy of a block that will call recursive_copy_block recursively\n");
+
+ recursive_copy_block = Block_copy(^(int i) {
+ if (verbose) printf("%d\n", i);
+ if (i > 0) {
+ recursive_copy_block(i - 1);
+ }
+ });
+
+ if (verbose) printf("recursive_copy_block's address is %p, running it:\n", (void*)recursive_copy_block);
+
+ recursive_copy_block(5);
+
+ printf("%s: Success\n", argv[0]);
+ return 0;
+}
diff --git a/test/BlocksRuntime/recursiveassign.c b/test/BlocksRuntime/recursiveassign.c
new file mode 100644
index 000000000000..f0070cbe5c93
--- /dev/null
+++ b/test/BlocksRuntime/recursiveassign.c
@@ -0,0 +1,44 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+/*
+ * recursiveassign.c
+ * testObjects
+ *
+ * Created by Blaine Garst on 12/3/08.
+ *
+ */
+
+// CONFIG rdar://6639533
+
+// The compiler is prefetching x->forwarding before evaluting code that recomputes forwarding and so the value goes to a place that is never seen again.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <Block.h>
+
+
+int main(int argc, char* argv[]) {
+
+ __block void (^recursive_copy_block)(int) = ^(int arg) { printf("got wrong Block\n"); exit(1); };
+
+
+ recursive_copy_block = Block_copy(^(int i) {
+ if (i > 0) {
+ recursive_copy_block(i - 1);
+ }
+ else {
+ printf("done!\n");
+ }
+ });
+
+
+ recursive_copy_block(5);
+
+ printf("%s: Success\n", argv[0]);
+ return 0;
+}
+
diff --git a/test/BlocksRuntime/reference.C b/test/BlocksRuntime/reference.C
new file mode 100644
index 000000000000..f86f11e86ce1
--- /dev/null
+++ b/test/BlocksRuntime/reference.C
@@ -0,0 +1,95 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+#import <Block.h>
+#import <stdio.h>
+#import <stdlib.h>
+
+// CONFIG C++
+
+int recovered = 0;
+
+
+
+int constructors = 0;
+int destructors = 0;
+
+#define CONST const
+
+class TestObject
+{
+public:
+ TestObject(CONST TestObject& inObj);
+ TestObject();
+ ~TestObject();
+
+ TestObject& operator=(CONST TestObject& inObj);
+
+ void test(void);
+
+ int version() CONST { return _version; }
+private:
+ mutable int _version;
+};
+
+TestObject::TestObject(CONST TestObject& inObj)
+
+{
+ ++constructors;
+ _version = inObj._version;
+ //printf("%p (%d) -- TestObject(const TestObject&) called", this, _version);
+}
+
+
+TestObject::TestObject()
+{
+ _version = ++constructors;
+ //printf("%p (%d) -- TestObject() called\n", this, _version);
+}
+
+
+TestObject::~TestObject()
+{
+ //printf("%p -- ~TestObject() called\n", this);
+ ++destructors;
+}
+
+#if 1
+TestObject& TestObject::operator=(CONST TestObject& inObj)
+{
+ //printf("%p -- operator= called", this);
+ _version = inObj._version;
+ return *this;
+}
+#endif
+
+void TestObject::test(void) {
+ void (^b)(void) = ^{ recovered = _version; };
+ void (^b2)(void) = Block_copy(b);
+ b2();
+ Block_release(b2);
+}
+
+
+
+void testRoutine() {
+ TestObject one;
+
+
+ one.test();
+}
+
+
+
+int main(int argc, char *argv[]) {
+ testRoutine();
+ if (recovered == 1) {
+ printf("%s: success\n", argv[0]);
+ exit(0);
+ }
+ printf("%s: *** didn't recover byref block variable\n", argv[0]);
+ exit(1);
+}
diff --git a/test/BlocksRuntime/rettypepromotion.c b/test/BlocksRuntime/rettypepromotion.c
new file mode 100644
index 000000000000..597eafe8b858
--- /dev/null
+++ b/test/BlocksRuntime/rettypepromotion.c
@@ -0,0 +1,36 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+/*
+ * rettypepromotion.c
+ * testObjects
+ *
+ * Created by Blaine Garst on 11/3/08.
+ *
+ */
+
+// CONFIG error:
+// C++ and C give different errors so we don't check for an exact match.
+// The error is that enum's are defined to be ints, always, even if defined with explicit long values
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+enum { LESS = -1, EQUAL, GREATER };
+
+void sortWithBlock(long (^comp)(void *arg1, void *arg2)) {
+}
+
+int main(int argc, char *argv[]) {
+ sortWithBlock(^(void *arg1, void *arg2) {
+ if (random()) return LESS;
+ if (random()) return EQUAL;
+ if (random()) return GREATER;
+ });
+ printf("%s: Success\n", argv[0]);
+ return 0;
+}
diff --git a/test/BlocksRuntime/returnfunctionptr.c b/test/BlocksRuntime/returnfunctionptr.c
new file mode 100644
index 000000000000..6c7df631f8db
--- /dev/null
+++ b/test/BlocksRuntime/returnfunctionptr.c
@@ -0,0 +1,23 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+
+// CONFIG rdar://6339747 but wasn't
+
+#include <stdio.h>
+
+int (*funcptr)(long);
+
+int (*(^b)(char))(long);
+
+int main(int argc, char *argv[]) {
+ // implicit is fine
+ b = ^(char x) { return funcptr; };
+ // explicit never parses
+ b = ^int (*(char x))(long) { return funcptr; };
+ printf("%s: Success\n", argv[0]);
+ return 0;
+}
diff --git a/test/BlocksRuntime/shorthandexpression.c b/test/BlocksRuntime/shorthandexpression.c
new file mode 100644
index 000000000000..bf4582072b48
--- /dev/null
+++ b/test/BlocksRuntime/shorthandexpression.c
@@ -0,0 +1,24 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+/*
+ * shorthandexpression.c
+ * testObjects
+ *
+ * Created by Blaine Garst on 9/16/08.
+ *
+ * CONFIG error:
+ */
+
+
+void foo() {
+ void (^b)(void) = ^(void)printf("hello world\n");
+}
+
+int main(int argc, char *argv[]) {
+ printf("%s: this shouldn't compile\n", argv[0]);
+ return 1;
+}
diff --git a/test/BlocksRuntime/sizeof.c b/test/BlocksRuntime/sizeof.c
new file mode 100644
index 000000000000..1f84fc16f38f
--- /dev/null
+++ b/test/BlocksRuntime/sizeof.c
@@ -0,0 +1,26 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+/*
+ * sizeof.c
+ * testObjects
+ *
+ * Created by Blaine Garst on 2/17/09.
+ *
+ */
+
+#include <stdio.h>
+
+// CONFIG error:
+
+int main(int argc, char *argv[]) {
+
+ void (^aBlock)(void) = ^{ printf("hellow world\n"); };
+
+ printf("the size of a block is %ld\n", sizeof(*aBlock));
+ printf("%s: success\n", argv[0]);
+ return 0;
+}
diff --git a/test/BlocksRuntime/small-struct.c b/test/BlocksRuntime/small-struct.c
new file mode 100644
index 000000000000..434f3c179f7e
--- /dev/null
+++ b/test/BlocksRuntime/small-struct.c
@@ -0,0 +1,45 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+// -*- mode:C; c-basic-offset:4; tab-width:4; intent-tabs-mode:nil; -*-
+// CONFIG
+
+#import <stdio.h>
+#import <stdlib.h>
+#import <string.h>
+
+typedef struct {
+ int a;
+ int b;
+} MiniStruct;
+
+int main (int argc, const char * argv[]) {
+ MiniStruct inny;
+ MiniStruct outty;
+ MiniStruct (^copyStruct)(MiniStruct);
+
+ memset(&inny, 0xA5, sizeof(inny));
+ memset(&outty, 0x2A, sizeof(outty));
+
+ inny.a = 12;
+ inny.b = 42;
+
+ copyStruct = ^(MiniStruct aTinyStruct){ return aTinyStruct; }; // pass-by-value intrinsically copies the argument
+
+ outty = copyStruct(inny);
+
+ if ( &inny == &outty ) {
+ printf("%s: struct wasn't copied.", argv[0]);
+ exit(1);
+ }
+ if ( (inny.a != outty.a) || (inny.b != outty.b) ) {
+ printf("%s: struct contents did not match.", argv[0]);
+ exit(1);
+ }
+
+ printf("%s: success\n", argv[0]);
+ return 0;
+}
diff --git a/test/BlocksRuntime/structmember.c b/test/BlocksRuntime/structmember.c
new file mode 100644
index 000000000000..c451d3f348c9
--- /dev/null
+++ b/test/BlocksRuntime/structmember.c
@@ -0,0 +1,45 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+/*
+ * structmember.c
+ * testObjects
+ *
+ * Created by Blaine Garst on 9/30/08.
+ * CONFIG
+ */
+#include <Block.h>
+#include <Block_private.h>
+#include <stdio.h>
+
+// CONFIG
+
+int main(int argc, char *argv[]) {
+ struct stuff {
+ long int a;
+ long int b;
+ long int c;
+ } localStuff = { 10, 20, 30 };
+ int d;
+
+ void (^a)(void) = ^ { printf("d is %d", d); };
+ void (^b)(void) = ^ { printf("d is %d, localStuff.a is %lu", d, localStuff.a); };
+
+ unsigned nominalsize = Block_size(b) - Block_size(a);
+#if __cplusplus__
+ // need copy+dispose helper for C++ structures
+ nominalsize += 2*sizeof(void*);
+#endif
+ if ((Block_size(b) - Block_size(a)) != nominalsize) {
+ printf("sizeof a is %ld, sizeof b is %ld, expected %d\n", Block_size(a), Block_size(b), nominalsize);
+ printf("dump of b is %s\n", _Block_dump(b));
+ return 1;
+ }
+ printf("%s: Success\n", argv[0]);
+ return 0;
+}
+
+
diff --git a/test/BlocksRuntime/testfilerunner.h b/test/BlocksRuntime/testfilerunner.h
new file mode 100644
index 000000000000..d4e54f029047
--- /dev/null
+++ b/test/BlocksRuntime/testfilerunner.h
@@ -0,0 +1,110 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+//
+// testfilerunner.h
+// testObjects
+//
+// Created by Blaine Garst on 9/24/08.
+//
+
+#import <Cocoa/Cocoa.h>
+
+/*
+ variations:
+ four source types: C, ObjC, C++, ObjC++,
+ and for ObjC or ObjC++ we have
+ RR and GC capabilities
+ we assume C++ friendly includes for C/ObjC even if C++ isn't used
+
+
+ four compilers: C, ObjC, C++, ObjC++
+ and for ObjC or ObjC++ we can compile
+ RR, RR+GC, GC+RR, GC
+ although to test RR+GC we need to build a shell "main" in both modes
+ and/or run with GC disabled if possible.
+
+ To maximize coverage we mark files with capabilities and then ask them to be
+ compiled with each variation of compiler and option.
+ If the file doesn't have the capability it politely refuses.
+*/
+
+enum options {
+ Do64 = (1 << 0),
+ DoCPP = (1 << 1),
+ DoOBJC = (1 << 3),
+ DoGC = (1 << 4),
+ DoRR = (1 << 5),
+ DoRRGC = (1 << 6), // -fobjc-gc but main w/o so it runs in RR mode
+ DoGCRR = (1 << 7), // -fobjc-gc & run GC mode
+
+ //DoDashG = (1 << 8),
+ DoDashO = (1 << 9),
+ DoDashOs = (1 << 10),
+ DoDashO2 = (1 << 11),
+
+ DoC99 = (1 << 12), // -std=c99
+};
+
+
+@class TestFileExeGenerator;
+
+// this class will actually compile and/or run a target binary
+// XXX we don't track which dynamic libraries requested/used nor set them up
+@interface TestFileExe : NSObject {
+ NSPointerArray *compileLine;
+ int options;
+ bool shouldFail;
+ TestFileExeGenerator *generator;
+ __strong char *binaryName;
+ __strong char *sourceName;
+ __strong char *libraryPath;
+ __strong char *frameworkPath;
+}
+@property int options;
+@property(assign) NSPointerArray *compileLine;
+@property(assign) TestFileExeGenerator *generator;
+@property bool shouldFail;
+@property __strong char *binaryName;
+@property __strong char *sourceName;
+@property __strong char *libraryPath;
+@property __strong char *frameworkPath;
+- (bool) compileUnlessExists:(bool)skip;
+- (bool) run;
+@property(readonly) __strong char *radar;
+@end
+
+// this class generates an appropriate set of configurations to compile
+// we don't track which gcc we use but we should XXX
+@interface TestFileExeGenerator : NSObject {
+ bool hasObjC;
+ bool hasRR;
+ bool hasGC;
+ bool hasCPlusPlus;
+ bool wantsC99;
+ bool wants64;
+ bool wants32;
+ bool supposedToNotCompile;
+ bool open; // this problem is still open - e.g. unresolved
+ __strong char *radar; // for things already known to go wrong
+ __strong char *filename;
+ __strong char *compilerPath;
+ __strong char *errorString;
+ __strong char *warningString;
+ NSPointerArray *extraLibraries;
+}
+@property bool hasObjC, hasRR, hasGC, hasCPlusPlus, wantsC99, supposedToNotCompile, open, wants32, wants64;
+@property(assign) __strong char *radar;
+@property __strong char *filename;
+@property __strong char *compilerPath;
+@property __strong char *errorString;
+@property __strong char *warningString;
+- (TestFileExe *)lineForOptions:(int)options; // nil if no can do
++ (NSArray *)generatorsFromFILE:(FILE *)fd;
++ (NSArray *)generatorsFromPath:(NSString *)path;
+@end
+
+
diff --git a/test/BlocksRuntime/testfilerunner.m b/test/BlocksRuntime/testfilerunner.m
new file mode 100644
index 000000000000..459adf889f6e
--- /dev/null
+++ b/test/BlocksRuntime/testfilerunner.m
@@ -0,0 +1,805 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+//
+// testfilerunner.m
+// testObjects
+//
+// Created by Blaine Garst on 9/24/08.
+//
+
+#import "testfilerunner.h"
+#import <Foundation/Foundation.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+bool Everything = false; // do it also with 3 levels of optimization
+bool DoClang = false;
+
+static bool isDirectory(char *path);
+static bool isExecutable(char *path);
+static bool isYounger(char *source, char *binary);
+static bool readErrorFile(char *buffer, const char *from);
+
+__strong char *gcstrcpy2(__strong const char *arg, char *endp) {
+ unsigned size = endp - arg + 1;
+ __strong char *result = NSAllocateCollectable(size, 0);
+ strncpy(result, arg, size);
+ result[size-1] = 0;
+ return result;
+}
+__strong char *gcstrcpy1(__strong char *arg) {
+ unsigned size = strlen(arg) + 1;
+ __strong char *result = NSAllocateCollectable(size, 0);
+ strncpy(result, arg, size);
+ result[size-1] = 0;
+ return result;
+}
+
+@implementation TestFileExe
+
+@synthesize options, compileLine, shouldFail, binaryName, sourceName;
+@synthesize generator;
+@synthesize libraryPath, frameworkPath;
+
+- (NSString *)description {
+ NSMutableString *result = [NSMutableString new];
+ if (shouldFail) [result appendString:@"fail"];
+ for (id x in compileLine) {
+ [result appendString:[NSString stringWithFormat:@" %s", (char *)x]];
+ }
+ return result;
+}
+
+- (__strong char *)radar {
+ return generator.radar;
+}
+
+- (bool) compileUnlessExists:(bool)skip {
+ if (shouldFail) {
+ printf("don't use this to compile anymore!\n");
+ return false;
+ }
+ if (skip && isExecutable(binaryName) && !isYounger(sourceName, binaryName)) return true;
+ int argc = [compileLine count];
+ char *argv[argc+1];
+ for (int i = 0; i < argc; ++i)
+ argv[i] = (char *)[compileLine pointerAtIndex:i];
+ argv[argc] = NULL;
+ pid_t child = fork();
+ if (child == 0) {
+ execv(argv[0], argv);
+ exit(10); // shouldn't happen
+ }
+ if (child < 0) {
+ printf("fork failed\n");
+ return false;
+ }
+ int status = 0;
+ pid_t deadchild = wait(&status);
+ if (deadchild != child) {
+ printf("wait got %d instead of %d\n", deadchild, child);
+ exit(1);
+ }
+ if (WEXITSTATUS(status) == 0) {
+ return true;
+ }
+ printf("run failed\n");
+ return false;
+}
+
+bool lookforIn(char *lookfor, const char *format, pid_t child) {
+ char buffer[512];
+ char got[512];
+ sprintf(buffer, format, child);
+ bool gotOutput = readErrorFile(got, buffer);
+ if (!gotOutput) {
+ printf("**** didn't get an output file %s to analyze!!??\n", buffer);
+ return false;
+ }
+ char *where = strstr(got, lookfor);
+ if (!where) {
+ printf("didn't find '%s' in output file %s\n", lookfor, buffer);
+ return false;
+ }
+ unlink(buffer);
+ return true;
+}
+
+- (bool) compileWithExpectedFailure {
+ if (!shouldFail) {
+ printf("Why am I being called?\n");
+ return false;
+ }
+ int argc = [compileLine count];
+ char *argv[argc+1];
+ for (int i = 0; i < argc; ++i)
+ argv[i] = (char *)[compileLine pointerAtIndex:i];
+ argv[argc] = NULL;
+ pid_t child = fork();
+ char buffer[512];
+ if (child == 0) {
+ // in child
+ sprintf(buffer, "/tmp/errorfile_%d", getpid());
+ close(1);
+ int fd = creat(buffer, 0777);
+ if (fd != 1) {
+ fprintf(stderr, "didn't open custom error file %s as 1, got %d\n", buffer, fd);
+ exit(1);
+ }
+ close(2);
+ dup(1);
+ int result = execv(argv[0], argv);
+ exit(10);
+ }
+ if (child < 0) {
+ printf("fork failed\n");
+ return false;
+ }
+ int status = 0;
+ pid_t deadchild = wait(&status);
+ if (deadchild != child) {
+ printf("wait got %d instead of %d\n", deadchild, child);
+ exit(11);
+ }
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) == 0) {
+ return false;
+ }
+ }
+ else {
+ printf("***** compiler borked/ICEd/died unexpectedly (status %x)\n", status);
+ return false;
+ }
+ char *error = generator.errorString;
+
+ if (!error) return true;
+#if 0
+ char got[512];
+ sprintf(buffer, "/tmp/errorfile_%d", child);
+ bool gotOutput = readErrorFile(got, buffer);
+ if (!gotOutput) {
+ printf("**** didn't get an error file %s to analyze!!??\n", buffer);
+ return false;
+ }
+ char *where = strstr(got, error);
+ if (!where) {
+ printf("didn't find '%s' in error file %s\n", error, buffer);
+ return false;
+ }
+ unlink(buffer);
+#else
+ if (!lookforIn(error, "/tmp/errorfile_%d", child)) return false;
+#endif
+ return true;
+}
+
+- (bool) run {
+ if (shouldFail) return true;
+ if (sizeof(long) == 4 && options & Do64) {
+ return true; // skip 64-bit tests
+ }
+ int argc = 1;
+ char *argv[argc+1];
+ argv[0] = binaryName;
+ argv[argc] = NULL;
+ pid_t child = fork();
+ if (child == 0) {
+ // set up environment
+ char lpath[1024];
+ char fpath[1024];
+ char *myenv[3];
+ int counter = 0;
+ if (libraryPath) {
+ sprintf(lpath, "DYLD_LIBRARY_PATH=%s", libraryPath);
+ myenv[counter++] = lpath;
+ }
+ if (frameworkPath) {
+ sprintf(fpath, "DYLD_FRAMEWORK_PATH=%s", frameworkPath);
+ myenv[counter++] = fpath;
+ }
+ myenv[counter] = NULL;
+ if (generator.warningString) {
+ // set up stdout/stderr
+ char outfile[1024];
+ sprintf(outfile, "/tmp/stdout_%d", getpid());
+ close(2);
+ close(1);
+ creat(outfile, 0700);
+ dup(1);
+ }
+ execve(argv[0], argv, myenv);
+ exit(10); // shouldn't happen
+ }
+ if (child < 0) {
+ printf("fork failed\n");
+ return false;
+ }
+ int status = 0;
+ pid_t deadchild = wait(&status);
+ if (deadchild != child) {
+ printf("wait got %d instead of %d\n", deadchild, child);
+ exit(1);
+ }
+ if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+ if (generator.warningString) {
+ if (!lookforIn(generator.warningString, "/tmp/stdout_%d", child)) return false;
+ }
+ return true;
+ }
+ printf("**** run failed for %s\n", binaryName);
+ return false;
+}
+
+@end
+
+@implementation TestFileExeGenerator
+@synthesize filename, compilerPath, errorString;
+@synthesize hasObjC, hasRR, hasGC, hasCPlusPlus, wantsC99, supposedToNotCompile, open, wants32, wants64;
+@synthesize radar;
+@synthesize warningString;
+
+- (void)setFilename:(__strong char *)name {
+ filename = gcstrcpy1(name);
+}
+- (void)setCompilerPath:(__strong char *)name {
+ compilerPath = gcstrcpy1(name);
+}
+
+- (void)forMostThings:(NSMutableArray *)lines options:(int)options {
+ TestFileExe *item = nil;
+ item = [self lineForOptions:options];
+ if (item) [lines addObject:item];
+ item = [self lineForOptions:options|Do64];
+ if (item) [lines addObject:item];
+ item = [self lineForOptions:options|DoCPP];
+ if (item) [lines addObject:item];
+ item = [self lineForOptions:options|Do64|DoCPP];
+ if (item) [lines addObject:item];
+}
+
+/*
+ DoDashG = (1 << 8),
+ DoDashO = (1 << 9),
+ DoDashOs = (1 << 10),
+ DoDashO2 = (1 << 11),
+*/
+
+- (void)forAllThings:(NSMutableArray *)lines options:(int)options {
+ [self forMostThings:lines options:options];
+ if (!Everything) {
+ return;
+ }
+ // now do it with three explicit optimization flags
+ [self forMostThings:lines options:options | DoDashO];
+ [self forMostThings:lines options:options | DoDashOs];
+ [self forMostThings:lines options:options | DoDashO2];
+}
+
+- (NSArray *)allLines {
+ NSMutableArray *result = [NSMutableArray new];
+ TestFileExe *item = nil;
+
+ int options = 0;
+ [self forAllThings:result options:0];
+ [self forAllThings:result options:DoOBJC | DoRR];
+ [self forAllThings:result options:DoOBJC | DoGC];
+ [self forAllThings:result options:DoOBJC | DoGCRR];
+ //[self forAllThings:result options:DoOBJC | DoRRGC];
+
+ return result;
+}
+
+- (void)addLibrary:(const char *)dashLSomething {
+ if (!extraLibraries) {
+ extraLibraries = [NSPointerArray pointerArrayWithOptions:
+ NSPointerFunctionsStrongMemory |
+ NSPointerFunctionsCStringPersonality];
+ }
+ [extraLibraries addPointer:(void *)dashLSomething];
+}
+
+- (TestFileExe *)lineForOptions:(int)options { // nil if no can do
+ if (hasObjC && !(options & DoOBJC)) return nil;
+ if (hasCPlusPlus && !(options & DoCPP)) return nil;
+ if (hasObjC) {
+ if (!hasGC && (options & (DoGC|DoGCRR))) return nil; // not smart enough
+ if (!hasRR && (options & (DoRR|DoRRGC))) return nil;
+ }
+ NSPointerArray *pa = [NSPointerArray pointerArrayWithOptions:
+ NSPointerFunctionsStrongMemory |
+ NSPointerFunctionsCStringPersonality];
+ // construct path
+ char path[512];
+ path[0] = 0;
+ if (!compilerPath) compilerPath = "/usr/bin";
+ if (compilerPath) {
+ strcat(path, compilerPath);
+ strcat(path, "/");
+ }
+ if (options & DoCPP) {
+ strcat(path, DoClang ? "clang++" : "g++-4.2");
+ }
+ else {
+ strcat(path, DoClang ? "clang" : "gcc-4.2");
+ }
+ [pa addPointer:gcstrcpy1(path)];
+ if (options & DoOBJC) {
+ if (options & DoCPP) {
+ [pa addPointer:"-ObjC++"];
+ }
+ else {
+ [pa addPointer:"-ObjC"];
+ }
+ }
+ [pa addPointer:"-g"];
+ if (options & DoDashO) [pa addPointer:"-O"];
+ else if (options & DoDashO2) [pa addPointer:"-O2"];
+ else if (options & DoDashOs) [pa addPointer:"-Os"];
+ if (wantsC99 && (! (options & DoCPP))) {
+ [pa addPointer:"-std=c99"];
+ [pa addPointer:"-fblocks"];
+ }
+ [pa addPointer:"-arch"];
+ [pa addPointer: (options & Do64) ? "x86_64" : "i386"];
+
+ if (options & DoOBJC) {
+ switch (options & (DoRR|DoGC|DoGCRR|DoRRGC)) {
+ case DoRR:
+ break;
+ case DoGC:
+ [pa addPointer:"-fobjc-gc-only"];
+ break;
+ case DoGCRR:
+ [pa addPointer:"-fobjc-gc"];
+ break;
+ case DoRRGC:
+ printf("DoRRGC unsupported right now\n");
+ [pa addPointer:"-c"];
+ return nil;
+ }
+ [pa addPointer:"-framework"];
+ [pa addPointer:"Foundation"];
+ }
+ [pa addPointer:gcstrcpy1(filename)];
+ [pa addPointer:"-o"];
+
+ path[0] = 0;
+ strcat(path, filename);
+ strcat(path, ".");
+ strcat(path, (options & Do64) ? "64" : "32");
+ if (options & DoOBJC) {
+ switch (options & (DoRR|DoGC|DoGCRR|DoRRGC)) {
+ case DoRR: strcat(path, "-rr"); break;
+ case DoGC: strcat(path, "-gconly"); break;
+ case DoGCRR: strcat(path, "-gcrr"); break;
+ case DoRRGC: strcat(path, "-rrgc"); break;
+ }
+ }
+ if (options & DoCPP) strcat(path, "++");
+ if (options & DoDashO) strcat(path, "-O");
+ else if (options & DoDashO2) strcat(path, "-O2");
+ else if (options & DoDashOs) strcat(path, "-Os");
+ if (wantsC99) strcat(path, "-C99");
+ strcat(path, DoClang ? "-clang" : "-gcc");
+ strcat(path, "-bin");
+ TestFileExe *result = [TestFileExe new];
+ result.binaryName = gcstrcpy1(path); // could snarf copy in pa
+ [pa addPointer:result.binaryName];
+ for (id cString in extraLibraries) {
+ [pa addPointer:cString];
+ }
+
+ result.sourceName = gcstrcpy1(filename); // could snarf copy in pa
+ result.compileLine = pa;
+ result.options = options;
+ result.shouldFail = supposedToNotCompile;
+ result.generator = self;
+ return result;
+}
+
++ (NSArray *)generatorsFromPath:(NSString *)path {
+ FILE *fp = fopen([path fileSystemRepresentation], "r");
+ if (fp == NULL) return nil;
+ NSArray *result = [self generatorsFromFILE:fp];
+ fclose(fp);
+ return result;
+}
+
+#define LOOKFOR "CON" "FIG"
+
+char *__strong parseRadar(char *line) {
+ line = strstr(line, "rdar:"); // returns beginning
+ char *endp = line + strlen("rdar:");
+ while (*endp && *endp != ' ' && *endp != '\n')
+ ++endp;
+ return gcstrcpy2(line, endp);
+}
+
+- (void)parseLibraries:(const char *)line {
+ start:
+ line = strstr(line, "-l");
+ char *endp = (char *)line + 2;
+ while (*endp && *endp != ' ' && *endp != '\n')
+ ++endp;
+ [self addLibrary:gcstrcpy2(line, endp)];
+ if (strstr(endp, "-l")) {
+ line = endp;
+ goto start;
+ }
+}
+
++ (TestFileExeGenerator *)generatorFromLine:(char *)line filename:(char *)filename {
+ TestFileExeGenerator *item = [TestFileExeGenerator new];
+ item.filename = gcstrcpy1(filename);
+ if (strstr(line, "GC")) item.hasGC = true;
+ if (strstr(line, "RR")) item.hasRR = true;
+ if (strstr(line, "C++")) item.hasCPlusPlus = true;
+ if (strstr(line, "-C99")) {
+ item.wantsC99 = true;
+ }
+ if (strstr(line, "64")) item.wants64 = true;
+ if (strstr(line, "32")) item.wants32 = true;
+ if (strstr(line, "-l")) [item parseLibraries:line];
+ if (strstr(line, "open")) item.open = true;
+ if (strstr(line, "FAIL")) item.supposedToNotCompile = true; // old
+ // compile time error
+ if (strstr(line, "error:")) {
+ item.supposedToNotCompile = true;
+ // zap newline
+ char *error = strstr(line, "error:") + strlen("error:");
+ // make sure we have something before the newline
+ char *newline = strstr(error, "\n");
+ if (newline && ((newline-error) > 1)) {
+ *newline = 0;
+ item.errorString = gcstrcpy1(strstr(line, "error:") + strlen("error: "));
+ }
+ }
+ // run time warning
+ if (strstr(line, "runtime:")) {
+ // zap newline
+ char *error = strstr(line, "runtime:") + strlen("runtime:");
+ // make sure we have something before the newline
+ char *newline = strstr(error, "\n");
+ if (newline && ((newline-error) > 1)) {
+ *newline = 0;
+ item.warningString = gcstrcpy1(strstr(line, "runtime:") + strlen("runtime:"));
+ }
+ }
+ if (strstr(line, "rdar:")) item.radar = parseRadar(line);
+ if (item.hasGC || item.hasRR) item.hasObjC = true;
+ if (!item.wants32 && !item.wants64) { // give them both if they ask for neither
+ item.wants32 = item.wants64 = true;
+ }
+ return item;
+}
+
++ (NSArray *)generatorsFromFILE:(FILE *)fp {
+ NSMutableArray *result = [NSMutableArray new];
+ // pretend this is a grep LOOKFOR *.[cmCM][cmCM] input
+ // look for
+ // filename: ... LOOKFOR [GC] [RR] [C++] [FAIL ...]
+ char buf[512];
+ while (fgets(buf, 512, fp)) {
+ char *config = strstr(buf, LOOKFOR);
+ if (!config) continue;
+ char *filename = buf;
+ char *end = strchr(buf, ':');
+ *end = 0;
+ [result addObject:[self generatorFromLine:config filename:filename]];
+ }
+ return result;
+}
+
++ (TestFileExeGenerator *)generatorFromFilename:(char *)filename {
+ FILE *fp = fopen(filename, "r");
+ if (!fp) {
+ printf("didn't open %s!!\n", filename);
+ return nil;
+ }
+ char buf[512];
+ while (fgets(buf, 512, fp)) {
+ char *config = strstr(buf, LOOKFOR);
+ if (!config) continue;
+ fclose(fp);
+ return [self generatorFromLine:config filename:filename];
+ }
+ fclose(fp);
+ // guess from filename
+ char *ext = strrchr(filename, '.');
+ if (!ext) return nil;
+ TestFileExeGenerator *result = [TestFileExeGenerator new];
+ result.filename = gcstrcpy1(filename);
+ if (!strncmp(ext, ".m", 2)) {
+ result.hasObjC = true;
+ result.hasRR = true;
+ result.hasGC = true;
+ }
+ else if (!strcmp(ext, ".c")) {
+ ;
+ }
+ else if (!strcmp(ext, ".M") || !strcmp(ext, ".mm")) {
+ result.hasObjC = true;
+ result.hasRR = true;
+ result.hasGC = true;
+ result.hasCPlusPlus = true;
+ }
+ else if (!strcmp(ext, ".cc")
+ || !strcmp(ext, ".cp")
+ || !strcmp(ext, ".cxx")
+ || !strcmp(ext, ".cpp")
+ || !strcmp(ext, ".CPP")
+ || !strcmp(ext, ".c++")
+ || !strcmp(ext, ".C")) {
+ result.hasCPlusPlus = true;
+ }
+ else {
+ printf("unknown extension, file %s ignored\n", filename);
+ result = nil;
+ }
+ return result;
+
+}
+
+- (NSString *)description {
+ return [NSString stringWithFormat:@"%s: %s%s%s%s%s%s",
+ filename,
+ LOOKFOR,
+ hasGC ? " GC" : "",
+ hasRR ? " RR" : "",
+ hasCPlusPlus ? " C++" : "",
+ wantsC99 ? "C99" : "",
+ supposedToNotCompile ? " FAIL" : ""];
+}
+
+@end
+
+void printDetails(NSArray *failures, const char *whatAreThey) {
+ if ([failures count]) {
+ NSMutableString *output = [NSMutableString new];
+ printf("%s:\n", whatAreThey);
+ for (TestFileExe *line in failures) {
+ printf("%s", line.binaryName);
+ char *radar = line.generator.radar;
+ if (radar)
+ printf(" (due to %s?),", radar);
+ printf(" recompile via:\n%s\n\n", line.description.UTF8String);
+ }
+ printf("\n");
+ }
+}
+
+void help(const char *whoami) {
+ printf("Usage: %s [-fast] [-e] [-dyld librarypath] [gcc4.2dir] [-- | source1 ...]\n", whoami);
+ printf(" -fast don't recompile if binary younger than source\n");
+ printf(" -open only run tests that are thought to still be unresolved\n");
+ printf(" -clang use the clang and clang++ compilers\n");
+ printf(" -e compile all variations also with -Os, -O2, -O3\n");
+ printf(" -dyld p override DYLD_LIBRARY_PATH and DYLD_FRAMEWORK_PATH to p when running tests\n");
+ printf(" <compilerpath> directory containing gcc-4.2 (or clang) that you wish to use to compile the tests\n");
+ printf(" -- assume stdin is a grep CON" "FIG across the test sources\n");
+ printf(" otherwise treat each remaining argument as a single test file source\n");
+ printf("%s will compile and run individual test files under a variety of compilers, c, obj-c, c++, and objc++\n", whoami);
+ printf(" .c files are compiled with all four compilers\n");
+ printf(" .m files are compiled with objc and objc++ compilers\n");
+ printf(" .C files are compiled with c++ and objc++ compilers\n");
+ printf(" .M files are compiled only with the objc++ compiler\n");
+ printf("(actually all forms of extensions recognized by the compilers are honored, .cc, .c++ etc.)\n");
+ printf("\nTest files should run to completion with no output and exit (return) 0 on success.\n");
+ printf("Further they should be able to be compiled and run with GC on or off and by the C++ compilers\n");
+ printf("A line containing the string CON" "FIG within the source enables restrictions to the above assumptions\n");
+ printf("and other options.\n");
+ printf("Following CON" "FIG the string\n");
+ printf(" C++ restricts the test to only be run by c++ and objc++ compilers\n");
+ printf(" GC restricts the test to only be compiled and run with GC on\n");
+ printf(" RR (retain/release) restricts the test to only be compiled and run with GC off\n");
+ printf("Additionally,\n");
+ printf(" -C99 restricts the C versions of the test to -fstd=c99 -fblocks\n");
+ printf(" -O adds the -O optimization level\n");
+ printf(" -O2 adds the -O2 optimization level\n");
+ printf(" -Os adds the -Os optimization level\n");
+ printf("Files that are known to exhibit unresolved problems can provide the term \"open\" and this can");
+ printf("in turn allow highlighting of fixes that have regressed as well as identify that fixes are now available.\n");
+ printf("Files that exhibit known bugs may provide\n");
+ printf(" rdar://whatever such that if they fail the rdar will get cited\n");
+ printf("Files that are expected to fail to compile should provide, as their last token sequence,\n");
+ printf(" error:\n");
+ printf(" or error: substring to match.\n");
+ printf("Files that are expected to produce a runtime error message should provide, as their last token sequence,\n");
+ printf(" warning: string to match\n");
+ printf("\n%s will compile and run all configurations of the test files and report a summary at the end. Good luck.\n", whoami);
+ printf(" Blaine Garst blaine@apple.com\n");
+}
+
+int main(int argc, char *argv[]) {
+ printf("running on %s-bit architecture\n", sizeof(long) == 4 ? "32" : "64");
+ char *compilerDir = "/usr/bin";
+ NSMutableArray *generators = [NSMutableArray new];
+ bool doFast = false;
+ bool doStdin = false;
+ bool onlyOpen = false;
+ char *libraryPath = getenv("DYLD_LIBRARY_PATH");
+ char *frameworkPath = getenv("DYLD_FRAMEWORK_PATH");
+ // process options
+ while (argc > 1) {
+ if (!strcmp(argv[1], "-fast")) {
+ doFast = true;
+ --argc;
+ ++argv;
+ }
+ else if (!strcmp(argv[1], "-dyld")) {
+ doFast = true;
+ --argc;
+ ++argv;
+ frameworkPath = argv[1];
+ libraryPath = argv[1];
+ --argc;
+ ++argv;
+ }
+ else if (!strcmp(argv[1], "-open")) {
+ onlyOpen = true;
+ --argc;
+ ++argv;
+ }
+ else if (!strcmp(argv[1], "-clang")) {
+ DoClang = true;
+ --argc;
+ ++argv;
+ }
+ else if (!strcmp(argv[1], "-e")) {
+ Everything = true;
+ --argc;
+ ++argv;
+ }
+ else if (!strcmp(argv[1], "--")) {
+ doStdin = true;
+ --argc;
+ ++argv;
+ }
+ else if (!strcmp(argv[1], "-")) {
+ help(argv[0]);
+ return 1;
+ }
+ else if (argc > 1 && isDirectory(argv[1])) {
+ compilerDir = argv[1];
+ ++argv;
+ --argc;
+ }
+ else
+ break;
+ }
+ // process remaining arguments, or stdin
+ if (argc == 1) {
+ if (doStdin)
+ generators = (NSMutableArray *)[TestFileExeGenerator generatorsFromFILE:stdin];
+ else {
+ help(argv[0]);
+ return 1;
+ }
+ }
+ else while (argc > 1) {
+ TestFileExeGenerator *generator = [TestFileExeGenerator generatorFromFilename:argv[1]];
+ if (generator) [generators addObject:generator];
+ ++argv;
+ --argc;
+ }
+ // see if we can generate all possibilities
+ NSMutableArray *failureToCompile = [NSMutableArray new];
+ NSMutableArray *failureToFailToCompile = [NSMutableArray new];
+ NSMutableArray *failureToRun = [NSMutableArray new];
+ NSMutableArray *successes = [NSMutableArray new];
+ for (TestFileExeGenerator *generator in generators) {
+ //NSLog(@"got %@", generator);
+ if (onlyOpen && !generator.open) {
+ //printf("skipping resolved test %s\n", generator.filename);
+ continue; // skip closed if onlyOpen
+ }
+ if (!onlyOpen && generator.open) {
+ //printf("skipping open test %s\n", generator.filename);
+ continue; // skip open if not asked for onlyOpen
+ }
+ generator.compilerPath = compilerDir;
+ NSArray *tests = [generator allLines];
+ for (TestFileExe *line in tests) {
+ line.frameworkPath = frameworkPath; // tell generators about it instead XXX
+ line.libraryPath = libraryPath; // tell generators about it instead XXX
+ if ([line shouldFail]) {
+ if (doFast) continue; // don't recompile & don't count as success
+ if ([line compileWithExpectedFailure]) {
+ [successes addObject:line];
+ }
+ else
+ [failureToFailToCompile addObject:line];
+ }
+ else if ([line compileUnlessExists:doFast]) {
+ if ([line run]) {
+ printf("%s ran successfully\n", line.binaryName);
+ [successes addObject:line];
+ }
+ else {
+ [failureToRun addObject:line];
+ }
+ }
+ else {
+ [failureToCompile addObject:line];
+ }
+ }
+ }
+ printf("\n--- results ---\n\n%lu successes\n%lu unexpected compile failures\n%lu failure to fail to compile errors\n%lu run failures\n",
+ [successes count], [failureToCompile count], [failureToFailToCompile count], [failureToRun count]);
+ printDetails(failureToCompile, "unexpected compile failures");
+ printDetails(failureToFailToCompile, "should have failed to compile but didn't failures");
+ printDetails(failureToRun, "run failures");
+
+ if (onlyOpen && [successes count]) {
+ NSMutableSet *radars = [NSMutableSet new];
+ printf("The following tests ran successfully suggesting that they are now resolved:\n");
+ for (TestFileExe *line in successes) {
+ printf("%s\n", line.binaryName);
+ if (line.radar) [radars addObject:line.generator];
+ }
+ if ([radars count]) {
+ printf("The following radars may be resolved:\n");
+ for (TestFileExeGenerator *line in radars) {
+ printf("%s\n", line.radar);
+ }
+ }
+ }
+
+ return [failureToCompile count] + [failureToRun count];
+}
+
+#include <sys/stat.h>
+
+static bool isDirectory(char *path) {
+ struct stat statb;
+ int retval = stat(path, &statb);
+ if (retval != 0) return false;
+ if (statb.st_mode & S_IFDIR) return true;
+ return false;
+}
+
+static bool isExecutable(char *path) {
+ struct stat statb;
+ int retval = stat(path, &statb);
+ if (retval != 0) return false;
+ if (!(statb.st_mode & S_IFREG)) return false;
+ if (statb.st_mode & S_IXUSR) return true;
+ return false;
+}
+
+static bool isYounger(char *source, char *binary) {
+ struct stat statb;
+ int retval = stat(binary, &statb);
+ if (retval != 0) return true; // if doesn't exit, lie
+
+ struct stat stata;
+ retval = stat(source, &stata);
+ if (retval != 0) return true; // we're hosed
+ // the greater the timeval the younger it is
+ if (stata.st_mtimespec.tv_sec > statb.st_mtimespec.tv_sec) return true;
+ if (stata.st_mtimespec.tv_nsec > statb.st_mtimespec.tv_nsec) return true;
+ return false;
+}
+
+static bool readErrorFile(char *buffer, const char *from) {
+ int fd = open(from, 0);
+ if (fd < 0) {
+ printf("didn't open %s, (might not have been created?)\n", buffer);
+ return false;
+ }
+ int count = read(fd, buffer, 512);
+ if (count < 1) {
+ printf("read error on %s\n", buffer);
+ return false;
+ }
+ buffer[count-1] = 0; // zap newline
+ return true;
+}
diff --git a/test/BlocksRuntime/varargs-bad-assign.c b/test/BlocksRuntime/varargs-bad-assign.c
new file mode 100644
index 000000000000..b978668b95c0
--- /dev/null
+++ b/test/BlocksRuntime/varargs-bad-assign.c
@@ -0,0 +1,44 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+// -*- mode:C; c-basic-offset:4; tab-width:4; intent-tabs-mode:nil; -*-
+// HACK ALERT: gcc and g++ give different errors, referencing the line number to ensure that it checks for the right error; MUST KEEP IN SYNC WITH THE TEST
+// CONFIG 27: error:
+
+#import <stdio.h>
+#import <stdlib.h>
+#import <string.h>
+#import <stdarg.h>
+
+
+int main (int argc, const char * argv[]) {
+ int (^sumn)(int n, ...);
+ int six = 0;
+
+ sumn = ^(int a, int b, int n, ...){
+ int result = 0;
+ va_list numbers;
+ int i;
+
+ va_start(numbers, n);
+ for (i = 0 ; i < n ; i++) {
+ result += va_arg(numbers, int);
+ }
+ va_end(numbers);
+
+ return result;
+ };
+
+ six = sumn(3, 1, 2, 3);
+
+ if ( six != 6 ) {
+ printf("%s: Expected 6 but got %d\n", argv[0], six);
+ exit(1);
+ }
+
+ printf("%s: success\n", argv[0]);
+ return 0;
+}
diff --git a/test/BlocksRuntime/varargs.c b/test/BlocksRuntime/varargs.c
new file mode 100644
index 000000000000..01affc76e68c
--- /dev/null
+++ b/test/BlocksRuntime/varargs.c
@@ -0,0 +1,39 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+// -*- mode:C; c-basic-offset:4; tab-width:4; intent-tabs-mode:nil; -*-
+// CONFIG
+
+#import <stdio.h>
+#import <stdlib.h>
+#import <string.h>
+#import <stdarg.h>
+
+
+int main (int argc, const char * argv[]) {
+ int (^sumn)(int n, ...) = ^(int n, ...){
+ int result = 0;
+ va_list numbers;
+ int i;
+
+ va_start(numbers, n);
+ for (i = 0 ; i < n ; i++) {
+ result += va_arg(numbers, int);
+ }
+ va_end(numbers);
+
+ return result;
+ };
+ int six = sumn(3, 1, 2, 3);
+
+ if ( six != 6 ) {
+ printf("%s: Expected 6 but got %d\n", argv[0], six);
+ exit(1);
+ }
+
+ printf("%s: success\n", argv[0]);
+ return 0;
+}
diff --git a/test/BlocksRuntime/variadic.c b/test/BlocksRuntime/variadic.c
new file mode 100644
index 000000000000..1d80657e9886
--- /dev/null
+++ b/test/BlocksRuntime/variadic.c
@@ -0,0 +1,66 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+/*
+ * variadic.c
+ * testObjects
+ *
+ * Created by Blaine Garst on 2/17/09.
+ *
+ */
+
+// PURPOSE Test that variadic arguments compile and work for Blocks
+// CONFIG
+
+#include <stdarg.h>
+#include <stdio.h>
+
+int main(int argc, char *argv[]) {
+
+ long (^addthem)(const char *, ...) = ^long (const char *format, ...){
+ va_list argp;
+ const char *p;
+ int i;
+ char c;
+ double d;
+ long result = 0;
+ va_start(argp, format);
+ //printf("starting...\n");
+ for (p = format; *p; p++) switch (*p) {
+ case 'i':
+ i = va_arg(argp, int);
+ //printf("i: %d\n", i);
+ result += i;
+ break;
+ case 'd':
+ d = va_arg(argp, double);
+ //printf("d: %g\n", d);
+ result += (int)d;
+ break;
+ case 'c':
+ c = va_arg(argp, int);
+ //printf("c: '%c'\n", c);
+ result += c;
+ break;
+ }
+ //printf("...done\n\n");
+ return result;
+ };
+ long testresult = addthem("ii", 10, 20);
+ if (testresult != 30) {
+ printf("got wrong result: %ld\n", testresult);
+ return 1;
+ }
+ testresult = addthem("idc", 30, 40.0, 'a');
+ if (testresult != (70+'a')) {
+ printf("got different wrong result: %ld\n", testresult);
+ return 1;
+ }
+ printf("%s: Success\n", argv[0]);
+ return 0;
+}
+
+
diff --git a/test/BlocksRuntime/voidarg.c b/test/BlocksRuntime/voidarg.c
new file mode 100644
index 000000000000..a8f034b47c10
--- /dev/null
+++ b/test/BlocksRuntime/voidarg.c
@@ -0,0 +1,27 @@
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+/*
+ * voidarg.c
+ * testObjects
+ *
+ * Created by Blaine Garst on 2/17/09.
+ *
+ */
+
+// PURPOSE should complain about missing 'void' but both GCC and clang are supporting K&R instead
+// CONFIG open error:
+
+#include <stdio.h>
+
+int Global;
+
+void (^globalBlock)() = ^{ ++Global; }; // should be void (^gb)(void) = ...
+
+int main(int argc, char *argv[]) {
+ printf("%s: success", argv[0]);
+ return 0;
+}
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644
index 000000000000..2ceb86463ae0
--- /dev/null
+++ b/test/CMakeLists.txt
@@ -0,0 +1,65 @@
+configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.common.configured.in
+ ${CMAKE_CURRENT_BINARY_DIR}/lit.common.configured)
+
+# BlocksRuntime and builtins testsuites are not yet ported to lit.
+# add_subdirectory(BlocksRuntime)
+# add_subdirectory(builtins)
+
+set(SANITIZER_COMMON_LIT_TEST_DEPS)
+# When ANDROID, we build tests with the host compiler (i.e. CMAKE_C_COMPILER),
+# and run tests with tools from the host toolchain.
+if(NOT ANDROID)
+ if(NOT COMPILER_RT_STANDALONE_BUILD)
+ # Use LLVM utils and Clang from the same build tree.
+ list(APPEND SANITIZER_COMMON_LIT_TEST_DEPS
+ clang clang-headers FileCheck count not llvm-nm llvm-symbolizer
+ compiler-rt-headers)
+ if (COMPILER_RT_HAS_PROFILE)
+ list(APPEND SANITIZER_COMMON_LIT_TEST_DEPS profile)
+ endif()
+ endif()
+ if(UNIX)
+ list(APPEND SANITIZER_COMMON_LIT_TEST_DEPS SanitizerLintCheck)
+ endif()
+endif()
+
+# Run sanitizer tests only if we're sure that clang would produce
+# working binaries.
+if(COMPILER_RT_CAN_EXECUTE_TESTS)
+ if(COMPILER_RT_HAS_ASAN)
+ add_subdirectory(asan)
+ endif()
+ if(COMPILER_RT_HAS_DFSAN)
+ add_subdirectory(dfsan)
+ endif()
+ if(COMPILER_RT_HAS_LSAN)
+ add_subdirectory(lsan)
+ endif()
+ if(COMPILER_RT_HAS_MSAN)
+ add_subdirectory(msan)
+ endif()
+ if(COMPILER_RT_HAS_PROFILE)
+ add_subdirectory(profile)
+ endif()
+ if(COMPILER_RT_HAS_SANITIZER_COMMON)
+ add_subdirectory(sanitizer_common)
+ endif()
+ if(COMPILER_RT_HAS_TSAN)
+ add_subdirectory(tsan)
+ endif()
+ if(COMPILER_RT_HAS_UBSAN)
+ add_subdirectory(ubsan)
+ endif()
+endif()
+
+if(COMPILER_RT_STANDALONE_BUILD)
+ # Now that we've traversed all the directories and know all the lit testsuites,
+ # introduce a rule to run to run all of them.
+ get_property(LLVM_LIT_TESTSUITES GLOBAL PROPERTY LLVM_LIT_TESTSUITES)
+ get_property(LLVM_LIT_DEPENDS GLOBAL PROPERTY LLVM_LIT_DEPENDS)
+ add_lit_target(check-all
+ "Running all regression tests"
+ ${LLVM_LIT_TESTSUITES}
+ DEPENDS ${LLVM_LIT_DEPENDS})
+endif()
diff --git a/test/asan/CMakeLists.txt b/test/asan/CMakeLists.txt
new file mode 100644
index 000000000000..14f7f506da51
--- /dev/null
+++ b/test/asan/CMakeLists.txt
@@ -0,0 +1,156 @@
+set(ASAN_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+
+set(ASAN_TESTSUITES)
+
+macro(get_bits_for_arch arch bits)
+ if (${arch} STREQUAL "arm" OR
+ ${arch} STREQUAL "i386" OR
+ ${arch} STREQUAL "i686" OR
+ ${arch} STREQUAL "mips")
+ set(bits 32)
+ elseif (${arch} STREQUAL "aarch64" OR
+ ${arch} STREQUAL "x86_64" OR
+ ${arch} STREQUAL "mips64")
+ set(bits 64)
+ else()
+ message(FATAL_ERROR "Unknown target architecture: ${arch}")
+ endif()
+endmacro()
+
+# TODO: merge with non-ANDROID case
+if(ANDROID)
+ foreach(arch ${ASAN_SUPPORTED_ARCH})
+ set(ASAN_TEST_TARGET_CC ${CMAKE_CXX_COMPILER})
+ set(ASAN_TEST_TARGET_CFLAGS ${COMPILER_RT_TEST_COMPILER_CFLAGS})
+ set(ASAN_TEST_CONFIG_SUFFIX "-${arch}-android")
+ get_bits_for_arch(${arch} ASAN_TEST_BITS)
+ set(ASAN_TEST_DYNAMIC True)
+ set(ASAN_TEST_TARGET_ARCH "${arch}-android")
+ string(TOUPPER ${arch} ARCH_UPPER_CASE)
+ set(CONFIG ${ARCH_UPPER_CASE}AndroidConfig)
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG}/lit.site.cfg
+ )
+ list(APPEND ASAN_TESTSUITES
+ ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG})
+ endforeach()
+
+else() # Not Android
+
+ if(CAN_TARGET_arm)
+ # This is only true if we are cross-compiling.
+ # Build all tests with host compiler and use host tools.
+ set(ASAN_TEST_TARGET_CC ${COMPILER_RT_TEST_COMPILER})
+ set(ASAN_TEST_TARGET_CFLAGS ${COMPILER_RT_TEST_COMPILER_CFLAGS})
+ set(ASAN_TEST_CONFIG_SUFFIX "-arm-linux")
+ set(ASAN_TEST_BITS "32")
+ set(ASAN_TEST_DYNAMIC False)
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/ARMLinuxConfig/lit.site.cfg
+ )
+ list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/ARMLinuxConfig)
+ endif()
+
+ if(CAN_TARGET_aarch64)
+ # This is only true if we are cross-compiling.
+ # Build all tests with host compiler and use host tools.
+ set(ASAN_TEST_TARGET_CC ${COMPILER_RT_TEST_COMPILER})
+ set(ASAN_TEST_TARGET_CFLAGS ${COMPILER_RT_TEST_COMPILER_CFLAGS})
+ set(ASAN_TEST_CONFIG_SUFFIX "-aarch64-linux")
+ set(ASAN_TEST_BITS "64")
+ set(ASAN_TEST_DYNAMIC False)
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/AArch64LinuxConfig/lit.site.cfg
+ )
+ list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/AArch64LinuxConfig)
+ endif()
+
+ if(CAN_TARGET_x86_64 OR CAN_TARGET_powerpc64 OR CAN_TARGET_mips64 OR CAN_TARGET_mips64el)
+ set(ASAN_TEST_CONFIG_SUFFIX "64")
+ set(ASAN_TEST_BITS "64")
+ set(ASAN_TEST_TARGET_CFLAGS ${TARGET_64_BIT_CFLAGS})
+ set(ASAN_TEST_DYNAMIC False)
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/64bitConfig/lit.site.cfg
+ )
+ list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/64bitConfig)
+ if(COMPILER_RT_BUILD_SHARED_ASAN)
+ set(ASAN_TEST_CONFIG_SUFFIX "64-Dynamic")
+ set(ASAN_TEST_DYNAMIC True)
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/64bitConfig-dynamic/lit.site.cfg)
+ list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/64bitConfig-dynamic)
+ endif()
+ endif()
+
+ if(CAN_TARGET_i386)
+ set(ASAN_TEST_CONFIG_SUFFIX "32")
+ set(ASAN_TEST_BITS "32")
+ set(ASAN_TEST_TARGET_CFLAGS ${TARGET_32_BIT_CFLAGS})
+ set(ASAN_TEST_DYNAMIC False)
+ set(ASAN_TEST_TARGET_ARCH "i386")
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig/lit.site.cfg
+ )
+ list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig)
+ if(COMPILER_RT_BUILD_SHARED_ASAN)
+ set(ASAN_TEST_CONFIG_SUFFIX "32-Dynamic")
+ set(ASAN_TEST_DYNAMIC True)
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig-dynamic/lit.site.cfg)
+ list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig-dynamic)
+ endif()
+ endif()
+
+ if(CAN_TARGET_mips OR CAN_TARGET_mipsel)
+ set(ASAN_TEST_CONFIG_SUFFIX "32")
+ set(ASAN_TEST_BITS "32")
+ set(ASAN_TEST_TARGET_CFLAGS ${TARGET_32_BIT_CFLAGS})
+ set(ASAN_TEST_DYNAMIC False)
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig/lit.site.cfg
+ )
+ list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig)
+ if(COMPILER_RT_BUILD_SHARED_ASAN)
+ set(ASAN_TEST_CONFIG_SUFFIX "32-Dynamic")
+ set(ASAN_TEST_DYNAMIC True)
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig-dynamic/lit.site.cfg)
+ list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig-dynamic)
+ endif()
+ endif()
+endif() # Not Android
+
+if(COMPILER_RT_INCLUDE_TESTS)
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg)
+endif()
+
+set(ASAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS})
+if(COMPILER_RT_STANDALONE_BUILD)
+ add_executable(FileCheck IMPORTED GLOBAL)
+ set_property(TARGET FileCheck PROPERTY IMPORTED_LOCATION ${LLVM_TOOLS_BINARY_DIR}/FileCheck)
+ list(APPEND ASAN_TEST_DEPS FileCheck)
+else()
+ list(APPEND ASAN_TEST_DEPS asan)
+endif()
+
+# FIXME: support unit test in the android test runner
+if(COMPILER_RT_INCLUDE_TESTS AND NOT ANDROID)
+ list(APPEND ASAN_TEST_DEPS AsanUnitTests)
+ list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit)
+endif()
+add_lit_testsuite(check-asan "Running the AddressSanitizer tests"
+ ${ASAN_TESTSUITES}
+ DEPENDS ${ASAN_TEST_DEPS})
+set_target_properties(check-asan PROPERTIES FOLDER "ASan tests")
diff --git a/test/asan/TestCases/Android/coverage-android.cc b/test/asan/TestCases/Android/coverage-android.cc
new file mode 100644
index 000000000000..071a2e3e1faa
--- /dev/null
+++ b/test/asan/TestCases/Android/coverage-android.cc
@@ -0,0 +1,67 @@
+// Test for direct coverage writing with dlopen.
+
+// Test normal exit.
+// RUN: %clangxx_asan -mllvm -asan-coverage=1 -DSHARED %s -shared -o %T/libcoverage_android_test_1.so -fPIC
+// RUN: %clangxx_asan -mllvm -asan-coverage=1 -DSO_DIR=\"%device\" %s -o %t
+
+// RUN: adb shell rm -rf %device/coverage-android
+// RUN: rm -rf %T/coverage-android
+
+// RUN: adb shell mkdir -p %device/coverage-android/direct
+// RUN: mkdir -p %T/coverage-android/direct
+// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=1:coverage_dir=%device/coverage-android/direct:verbosity=1 %run %t
+// RUN: adb pull %device/coverage-android/direct %T/coverage-android/direct
+// RUN: ls; pwd
+// RUN: cd %T/coverage-android/direct
+// RUN: %sancov rawunpack *.sancov.raw
+// RUN: %sancov print *.sancov |& FileCheck %s
+
+
+// Test sudden death.
+// RUN: %clangxx_asan -mllvm -asan-coverage=1 -DSHARED -DKILL %s -shared -o %T/libcoverage_android_test_1.so -fPIC
+// RUN: %clangxx_asan -mllvm -asan-coverage=1 -DSO_DIR=\"%device\" %s -o %t
+
+// RUN: adb shell rm -rf %device/coverage-android-kill
+// RUN: rm -rf %T/coverage-android-kill
+
+// RUN: adb shell mkdir -p %device/coverage-android-kill/direct
+// RUN: mkdir -p %T/coverage-android-kill/direct
+// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=1:coverage_dir=%device/coverage-android-kill/direct:verbosity=1 not %run %t
+// RUN: adb pull %device/coverage-android-kill/direct %T/coverage-android-kill/direct
+// RUN: ls; pwd
+// RUN: cd %T/coverage-android-kill/direct
+// RUN: %sancov rawunpack *.sancov.raw
+// RUN: %sancov print *.sancov |& FileCheck %s
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <signal.h>
+
+#ifdef SHARED
+extern "C" {
+void bar() {
+ printf("bar\n");
+#ifdef KILL
+ kill(getpid(), SIGKILL);
+#endif
+}
+}
+#else
+
+int main(int argc, char **argv) {
+ fprintf(stderr, "PID: %d\n", getpid());
+ void *handle1 =
+ dlopen(SO_DIR "/libcoverage_android_test_1.so", RTLD_LAZY);
+ assert(handle1);
+ void (*bar1)() = (void (*)())dlsym(handle1, "bar");
+ assert(bar1);
+ bar1();
+
+ return 0;
+}
+#endif
+
+// CHECK: 2 PCs total
diff --git a/test/asan/TestCases/Android/lit.local.cfg b/test/asan/TestCases/Android/lit.local.cfg
new file mode 100644
index 000000000000..42513dd3aa61
--- /dev/null
+++ b/test/asan/TestCases/Android/lit.local.cfg
@@ -0,0 +1,11 @@
+def getRoot(config):
+ if not config.parent:
+ return config
+ return getRoot(config.parent)
+
+root = getRoot(config)
+
+if root.android != "TRUE":
+ config.unsupported = True
+
+config.substitutions.append( ("%device", "/data/local/tmp/Output") )
diff --git a/test/asan/TestCases/Darwin/asan_gen_prefixes.cc b/test/asan/TestCases/Darwin/asan_gen_prefixes.cc
new file mode 100644
index 000000000000..13363ac47255
--- /dev/null
+++ b/test/asan/TestCases/Darwin/asan_gen_prefixes.cc
@@ -0,0 +1,14 @@
+// Make sure __asan_gen_* strings have the correct prefixes on Darwin
+// ("L" in __TEXT,__cstring, "l" in __TEXT,__const
+
+// RUN: %clang_asan %s -S -o %t.s
+// RUN: cat %t.s | FileCheck %s || exit 1
+
+int x, y, z;
+int main() { return 0; }
+// CHECK: .section{{.*}}__TEXT,__const
+// CHECK: l___asan_gen_
+// CHECK: .section{{.*}}__TEXT,__cstring,cstring_literals
+// CHECK: L___asan_gen_
+// CHECK: L___asan_gen_
+// CHECK: L___asan_gen_
diff --git a/test/asan/TestCases/Darwin/cstring_literals_regtest.mm b/test/asan/TestCases/Darwin/cstring_literals_regtest.mm
new file mode 100644
index 000000000000..bcb15d8f39b0
--- /dev/null
+++ b/test/asan/TestCases/Darwin/cstring_literals_regtest.mm
@@ -0,0 +1,23 @@
+// Regression test for
+// https://code.google.com/p/address-sanitizer/issues/detail?id=274.
+
+// RUN: %clang_asan %s -framework Foundation -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+#import <Foundation/Foundation.h>
+
+#include <stdio.h>
+
+int main() {
+ NSString* version_file = @"MAJOR=35\n";
+ int major = 0, minor = 0, build = 0, patch = 0;
+ NSScanner* scanner = [NSScanner scannerWithString:version_file];
+ NSString *res = nil;
+ if ([scanner scanString:@"MAJOR=" intoString:nil] &&
+ [scanner scanInt:&major]) {
+ res = [NSString stringWithFormat:@"%d.%d.%d.%d",
+ major, minor, build, patch];
+ }
+ printf("%s\n", [res UTF8String]);
+ // CHECK: 35.0.0.0
+ return 0;
+}
diff --git a/test/asan/TestCases/Darwin/dyld_insert_libraries_reexec.cc b/test/asan/TestCases/Darwin/dyld_insert_libraries_reexec.cc
new file mode 100644
index 000000000000..b1bb4567f900
--- /dev/null
+++ b/test/asan/TestCases/Darwin/dyld_insert_libraries_reexec.cc
@@ -0,0 +1,33 @@
+// When DYLD-inserting the ASan dylib from a different location than the
+// original, make sure we don't try to reexec.
+
+// RUN: mkdir -p %T/dyld_insert_libraries_reexec
+// RUN: cp `%clang_asan %s -fsanitize=address -### 2>&1 \
+// RUN: | grep "libclang_rt.asan_osx_dynamic.dylib" \
+// RUN: | sed -e 's/.*"\(.*libclang_rt.asan_osx_dynamic.dylib\)".*/\1/'` \
+// RUN: %T/dyld_insert_libraries_reexec/libclang_rt.asan_osx_dynamic.dylib
+// RUN: %clangxx_asan %s -o %T/dyld_insert_libraries_reexec/a.out
+// RUN: DYLD_INSERT_LIBRARIES=@executable_path/libclang_rt.asan_osx_dynamic.dylib \
+// RUN: ASAN_OPTIONS=verbosity=1 %run %T/dyld_insert_libraries_reexec/a.out 2>&1 \
+// RUN: | FileCheck %s
+// RUN: ASAN_OPTIONS=verbosity=1 %run %T/dyld_insert_libraries_reexec/a.out 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NOINSERT %s
+
+#include <stdio.h>
+
+int main() {
+ printf("Passed\n");
+ return 0;
+}
+
+// CHECK-NOINSERT: Parsed ASAN_OPTIONS: verbosity=1
+// CHECK-NOINSERT: exec()-ing the program with
+// CHECK-NOINSERT: DYLD_INSERT_LIBRARIES
+// CHECK-NOINSERT: to enable ASan wrappers.
+// CHECK-NOINSERT: Passed
+
+// CHECK: Parsed ASAN_OPTIONS: verbosity=1
+// CHECK-NOT: exec()-ing the program with
+// CHECK-NOT: DYLD_INSERT_LIBRARIES
+// CHECK-NOT: to enable ASan wrappers.
+// CHECK: Passed
diff --git a/test/asan/TestCases/Darwin/interception-in-shared-lib-test.cc b/test/asan/TestCases/Darwin/interception-in-shared-lib-test.cc
new file mode 100644
index 000000000000..e472a9dc6972
--- /dev/null
+++ b/test/asan/TestCases/Darwin/interception-in-shared-lib-test.cc
@@ -0,0 +1,32 @@
+// Check that memset() call from a shared library gets intercepted.
+// Please always keep this file in sync with
+// ../Linux/interception-in-shared-lib-test.cc.
+
+// RUN: %clangxx_asan -O0 %s -DSHARED_LIB \
+// RUN: -shared -o %T/libinterception-in-shared-lib-test.so \
+// RUN: -fPIC
+// TODO(glider): figure out how to set rpath in a more portable way and unite
+// this test with ../Linux/interception-in-shared-lib-test.cc.
+// RUN: %clangxx_asan -O0 %s -o %t -Wl,-rpath,@executable-path -L%T -linterception-in-shared-lib-test && \
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <string.h>
+
+#if defined(SHARED_LIB)
+extern "C"
+void my_memset(void *p, size_t sz) {
+ memset(p, 0, sz);
+}
+#else
+extern "C" void my_memset(void *p, size_t sz);
+
+int main(int argc, char *argv[]) {
+ char buf[10];
+ my_memset(buf, 11);
+ // CHECK: {{.*ERROR: AddressSanitizer: stack-buffer-overflow}}
+ // CHECK: {{WRITE of size 11 at 0x.* thread T0}}
+ // CHECK: {{0x.* in my_memset .*interception-in-shared-lib-test.cc:19}}
+ return 0;
+}
+#endif
diff --git a/test/asan/TestCases/Darwin/interface_symbols_darwin.c b/test/asan/TestCases/Darwin/interface_symbols_darwin.c
new file mode 100644
index 000000000000..8680d678cf91
--- /dev/null
+++ b/test/asan/TestCases/Darwin/interface_symbols_darwin.c
@@ -0,0 +1,39 @@
+// Check the presence of interface symbols in the ASan runtime dylib.
+// If you're changing this file, please also change
+// ../Linux/interface_symbols.c
+
+// RUN: %clang_asan -dead_strip -O2 %s -o %t.exe
+// RUN: rm -f %t.symbols %t.interface
+
+// RUN: nm -g `%clang_asan %s -fsanitize=address -### 2>&1 | grep "libclang_rt.asan_osx_dynamic.dylib" | sed -e 's/.*"\(.*libclang_rt.asan_osx_dynamic.dylib\)".*/\1/'` \
+// RUN: | grep " T " | sed "s/.* T //" \
+// RUN: | grep "__asan_" | sed "s/___asan_/__asan_/" \
+// RUN: | sed -E "s/__asan_init_v[0-9]+/__asan_init/" \
+// RUN: | grep -v "__asan_default_options" \
+// RUN: | grep -v "__asan_on_error" > %t.symbols
+
+// RUN: cat %p/../../../../lib/asan/asan_interface_internal.h \
+// RUN: | sed "s/\/\/.*//" | sed "s/typedef.*//" \
+// RUN: | grep -v "OPTIONAL" \
+// RUN: | grep "__asan_.*(" | sed "s/.* __asan_/__asan_/;s/(.*//" \
+// RUN: > %t.interface
+// RUN: echo __asan_report_load1 >> %t.interface
+// RUN: echo __asan_report_load2 >> %t.interface
+// RUN: echo __asan_report_load4 >> %t.interface
+// RUN: echo __asan_report_load8 >> %t.interface
+// RUN: echo __asan_report_load16 >> %t.interface
+// RUN: echo __asan_report_store1 >> %t.interface
+// RUN: echo __asan_report_store2 >> %t.interface
+// RUN: echo __asan_report_store4 >> %t.interface
+// RUN: echo __asan_report_store8 >> %t.interface
+// RUN: echo __asan_report_store16 >> %t.interface
+// RUN: echo __asan_report_load_n >> %t.interface
+// RUN: echo __asan_report_store_n >> %t.interface
+// RUN: echo __asan_get_current_fake_stack >> %t.interface
+// RUN: echo __asan_addr_is_in_fake_stack >> %t.interface
+// RUN: for i in `jot - 0 10`; do echo __asan_stack_malloc_$i >> %t.interface; done
+// RUN: for i in `jot - 0 10`; do echo __asan_stack_free_$i >> %t.interface; done
+
+// RUN: cat %t.interface | sort -u | diff %t.symbols -
+
+int main() { return 0; }
diff --git a/test/asan/TestCases/Darwin/lit.local.cfg b/test/asan/TestCases/Darwin/lit.local.cfg
new file mode 100644
index 000000000000..a85dfcd24c08
--- /dev/null
+++ b/test/asan/TestCases/Darwin/lit.local.cfg
@@ -0,0 +1,9 @@
+def getRoot(config):
+ if not config.parent:
+ return config
+ return getRoot(config.parent)
+
+root = getRoot(config)
+
+if root.host_os not in ['Darwin']:
+ config.unsupported = True
diff --git a/test/asan/TestCases/Darwin/malloc_set_zone_name-mprotect.cc b/test/asan/TestCases/Darwin/malloc_set_zone_name-mprotect.cc
new file mode 100644
index 000000000000..2c643bc03c52
--- /dev/null
+++ b/test/asan/TestCases/Darwin/malloc_set_zone_name-mprotect.cc
@@ -0,0 +1,51 @@
+// Regression test for a bug in malloc_create_zone()
+// (https://code.google.com/p/address-sanitizer/issues/detail?id=203)
+// The old implementation of malloc_create_zone() didn't always return a
+// page-aligned address, so we can only test on a best-effort basis.
+
+// RUN: %clangxx_asan %s -o %t
+// RUN: %run %t 2>&1
+
+#include <malloc/malloc.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+const int kNumIter = 4096;
+const int kNumZones = 100;
+int main() {
+ char *mem[kNumIter * 2];
+ // Allocate memory chunks from different size classes up to 1 page.
+ // (For the case malloc() returns memory chunks in descending order)
+ for (int i = 0; i < kNumIter; i++) {
+ mem[i] = (char*)malloc(8 * i);
+ }
+ // Try to allocate a page-aligned malloc zone. Otherwise the mprotect() call
+ // in malloc_set_zone_name() will silently fail.
+ malloc_zone_t *zone = NULL;
+ bool aligned = false;
+ for (int i = 0; i < kNumZones; i++) {
+ zone = malloc_create_zone(0, 0);
+ if (((uintptr_t)zone & (~0xfff)) == (uintptr_t)zone) {
+ aligned = true;
+ break;
+ }
+ }
+ if (!aligned) {
+ printf("Warning: couldn't allocate a page-aligned zone.");
+ return 0;
+ }
+ // malloc_set_zone_name() calls mprotect(zone, 4096, PROT_READ | PROT_WRITE),
+ // modifies the zone contents and then calls mprotect(zone, 4096, PROT_READ).
+ malloc_set_zone_name(zone, "foobar");
+ // Allocate memory chunks from different size classes again.
+ for (int i = 0; i < kNumIter; i++) {
+ mem[i + kNumIter] = (char*)malloc(8 * i);
+ }
+ // Access the allocated memory chunks and free them.
+ for (int i = 0; i < kNumIter * 2; i++) {
+ memset(mem[i], 'a', 8 * (i % kNumIter));
+ free(mem[i]);
+ }
+ return 0;
+}
diff --git a/test/asan/TestCases/Darwin/malloc_zone-protected.cc b/test/asan/TestCases/Darwin/malloc_zone-protected.cc
new file mode 100644
index 000000000000..362b60e20b55
--- /dev/null
+++ b/test/asan/TestCases/Darwin/malloc_zone-protected.cc
@@ -0,0 +1,20 @@
+// Make sure the zones created by malloc_create_zone() are write-protected.
+#include <malloc/malloc.h>
+#include <stdio.h>
+
+// RUN: %clangxx_asan %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+
+void *pwn(malloc_zone_t *unused_zone, size_t unused_size) {
+ printf("PWNED\n");
+ return NULL;
+}
+
+int main() {
+ malloc_zone_t *zone = malloc_create_zone(0, 0);
+ zone->malloc = pwn;
+ void *v = malloc_zone_malloc(zone, 1);
+ // CHECK-NOT: PWNED
+ return 0;
+}
diff --git a/test/asan/TestCases/Darwin/objc-odr.mm b/test/asan/TestCases/Darwin/objc-odr.mm
new file mode 100644
index 000000000000..72bc39c80dd4
--- /dev/null
+++ b/test/asan/TestCases/Darwin/objc-odr.mm
@@ -0,0 +1,23 @@
+// Regression test for
+// https://code.google.com/p/address-sanitizer/issues/detail?id=360.
+
+// RUN: %clang_asan %s -o %t -framework Foundation
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+void f() {
+ int y = 7;
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ printf("num = %d\n", y);
+ });
+ });
+}
+
+int main() {
+ NSLog(@"Hello world");
+}
+
+// CHECK-NOT: AddressSanitizer: odr-violation
+// CHECK: Hello world
diff --git a/test/asan/TestCases/Darwin/reexec-insert-libraries-env.cc b/test/asan/TestCases/Darwin/reexec-insert-libraries-env.cc
new file mode 100644
index 000000000000..59ddd634b400
--- /dev/null
+++ b/test/asan/TestCases/Darwin/reexec-insert-libraries-env.cc
@@ -0,0 +1,25 @@
+// Make sure ASan doesn't hang in an exec loop if DYLD_INSERT_LIBRARIES is set.
+// This is a regression test for
+// https://code.google.com/p/address-sanitizer/issues/detail?id=159
+
+// RUN: %clangxx_asan %s -o %t
+// RUN: %clangxx -DSHARED_LIB %s \
+// RUN: -dynamiclib -o darwin-dummy-shared-lib-so.dylib
+
+// FIXME: the following command line may hang in the case of a regression.
+// RUN: DYLD_INSERT_LIBRARIES=darwin-dummy-shared-lib-so.dylib \
+// RUN: %run %t 2>&1 | FileCheck %s || exit 1
+
+#if !defined(SHARED_LIB)
+#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+ const char kEnvName[] = "DYLD_INSERT_LIBRARIES";
+ printf("%s=%s\n", kEnvName, getenv(kEnvName));
+ // CHECK: {{DYLD_INSERT_LIBRARIES=.*darwin-dummy-shared-lib-so.dylib.*}}
+ return 0;
+}
+#else // SHARED_LIB
+void foo() {}
+#endif // SHARED_LIB
diff --git a/test/asan/TestCases/Darwin/suppressions-darwin.cc b/test/asan/TestCases/Darwin/suppressions-darwin.cc
new file mode 100644
index 000000000000..9a8f56d5dc50
--- /dev/null
+++ b/test/asan/TestCases/Darwin/suppressions-darwin.cc
@@ -0,0 +1,34 @@
+// Check that without suppressions, we catch the issue.
+// RUN: %clangxx_asan -O0 %s -o %t -framework Foundation
+// RUN: not %run %t 2>&1 | FileCheck --check-prefix=CHECK-CRASH %s
+
+// Check that suppressing the interceptor by name works.
+// RUN: echo "interceptor_name:memmove" > %t.supp
+// RUN: ASAN_OPTIONS=suppressions=%t.supp %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s
+
+// Check that suppressing by interceptor name works even without the symbolizer
+// RUN: ASAN_OPTIONS=suppressions=%t.supp:symbolize=false %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s
+
+// Check that suppressing all reports from a library works.
+// RUN: echo "interceptor_via_lib:CoreFoundation" > %t.supp
+// RUN: ASAN_OPTIONS=suppressions=%t.supp %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s
+
+// Check that suppressing library works even without the symbolizer.
+// RUN: ASAN_OPTIONS=suppressions=%t.supp:symbolize=false %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s
+
+#include <CoreFoundation/CoreFoundation.h>
+
+int main() {
+ char *a = (char *)malloc(6);
+ strcpy(a, "hello");
+ CFStringRef str =
+ CFStringCreateWithBytes(kCFAllocatorDefault, (unsigned char *)a, 10,
+ kCFStringEncodingUTF8, FALSE); // BOOM
+ fprintf(stderr, "Ignored.\n");
+ free(a);
+}
+
+// CHECK-CRASH: AddressSanitizer: heap-buffer-overflow
+// CHECK-CRASH-NOT: Ignored.
+// CHECK-IGNORE-NOT: AddressSanitizer: heap-buffer-overflow
+// CHECK-IGNORE: Ignored.
diff --git a/test/asan/TestCases/Darwin/unset-insert-libraries-on-exec.cc b/test/asan/TestCases/Darwin/unset-insert-libraries-on-exec.cc
new file mode 100644
index 000000000000..ed476b223af3
--- /dev/null
+++ b/test/asan/TestCases/Darwin/unset-insert-libraries-on-exec.cc
@@ -0,0 +1,25 @@
+// Make sure ASan removes the runtime library from DYLD_INSERT_LIBRARIES before
+// executing other programs.
+
+// RUN: %clangxx_asan %s -o %t
+// RUN: %clangxx %p/../Helpers/echo-env.cc -o %T/echo-env
+// RUN: %clangxx -DSHARED_LIB %s \
+// RUN: -dynamiclib -o %t-darwin-dummy-shared-lib-so.dylib
+
+// Make sure DYLD_INSERT_LIBRARIES doesn't contain the runtime library before
+// execl().
+
+// RUN: %run %t %T/echo-env >/dev/null 2>&1
+// RUN: DYLD_INSERT_LIBRARIES=%t-darwin-dummy-shared-lib-so.dylib \
+// RUN: %run %t %T/echo-env 2>&1 | FileCheck %s || exit 1
+
+#if !defined(SHARED_LIB)
+#include <unistd.h>
+int main(int argc, char *argv[]) {
+ execl(argv[1], argv[1], "DYLD_INSERT_LIBRARIES", NULL);
+ // CHECK: {{DYLD_INSERT_LIBRARIES = .*darwin-dummy-shared-lib-so.dylib.*}}
+ return 0;
+}
+#else // SHARED_LIB
+void foo() {}
+#endif // SHARED_LIB
diff --git a/test/asan/TestCases/Helpers/blacklist-extra.cc b/test/asan/TestCases/Helpers/blacklist-extra.cc
new file mode 100644
index 000000000000..627115cdda2b
--- /dev/null
+++ b/test/asan/TestCases/Helpers/blacklist-extra.cc
@@ -0,0 +1,5 @@
+// This function is broken, but this file is blacklisted
+int externalBrokenFunction(int argc) {
+ char x[10] = {0};
+ return x[argc * 10]; // BOOM
+}
diff --git a/test/asan/TestCases/Helpers/echo-env.cc b/test/asan/TestCases/Helpers/echo-env.cc
new file mode 100644
index 000000000000..65e91c155c84
--- /dev/null
+++ b/test/asan/TestCases/Helpers/echo-env.cc
@@ -0,0 +1,19 @@
+// Helper binary for
+// lit_tests/TestCases/Darwin/unset-insert-libraries-on-exec.cc
+// Prints the environment variable with the given name.
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char *argv[]) {
+ if (argc != 2) {
+ printf("Usage: %s ENVNAME\n", argv[0]);
+ exit(1);
+ }
+ const char *value = getenv(argv[1]);
+ if (value) {
+ printf("%s = %s\n", argv[1], value);
+ } else {
+ printf("%s not set.\n", argv[1]);
+ }
+ return 0;
+}
diff --git a/test/asan/TestCases/Helpers/init-order-atexit-extra.cc b/test/asan/TestCases/Helpers/init-order-atexit-extra.cc
new file mode 100644
index 000000000000..e4189d19d099
--- /dev/null
+++ b/test/asan/TestCases/Helpers/init-order-atexit-extra.cc
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+class C {
+ public:
+ C() { value = 42; }
+ ~C() { }
+ int value;
+};
+
+C c;
+
+void AccessC() {
+ printf("C value: %d\n", c.value);
+}
+
+int main() { return 0; }
diff --git a/test/asan/TestCases/Helpers/init-order-pthread-create-extra.cc b/test/asan/TestCases/Helpers/init-order-pthread-create-extra.cc
new file mode 100644
index 000000000000..d4606f0afb52
--- /dev/null
+++ b/test/asan/TestCases/Helpers/init-order-pthread-create-extra.cc
@@ -0,0 +1,2 @@
+void *bar(void *input);
+void *glob2 = bar((void*)0x2345);
diff --git a/test/asan/TestCases/Helpers/initialization-blacklist-extra.cc b/test/asan/TestCases/Helpers/initialization-blacklist-extra.cc
new file mode 100644
index 000000000000..09aed2112d5e
--- /dev/null
+++ b/test/asan/TestCases/Helpers/initialization-blacklist-extra.cc
@@ -0,0 +1,15 @@
+int zero_init() { return 0; }
+int badGlobal = zero_init();
+int readBadGlobal() { return badGlobal; }
+
+namespace badNamespace {
+class BadClass {
+ public:
+ BadClass() { value = 0; }
+ int value;
+};
+// Global object with non-trivial constructor.
+BadClass bad_object;
+} // namespace badNamespace
+
+int accessBadObject() { return badNamespace::bad_object.value; }
diff --git a/test/asan/TestCases/Helpers/initialization-blacklist-extra2.cc b/test/asan/TestCases/Helpers/initialization-blacklist-extra2.cc
new file mode 100644
index 000000000000..69455a0a6fc9
--- /dev/null
+++ b/test/asan/TestCases/Helpers/initialization-blacklist-extra2.cc
@@ -0,0 +1,4 @@
+int zero_init();
+int badSrcGlobal = zero_init();
+int readBadSrcGlobal() { return badSrcGlobal; }
+
diff --git a/test/asan/TestCases/Helpers/initialization-blacklist.txt b/test/asan/TestCases/Helpers/initialization-blacklist.txt
new file mode 100644
index 000000000000..83294635622d
--- /dev/null
+++ b/test/asan/TestCases/Helpers/initialization-blacklist.txt
@@ -0,0 +1,3 @@
+global:*badGlobal*=init
+type:*badNamespace::BadClass*=init
+src:*initialization-blacklist-extra2.cc=init
diff --git a/test/asan/TestCases/Helpers/initialization-bug-extra.cc b/test/asan/TestCases/Helpers/initialization-bug-extra.cc
new file mode 100644
index 000000000000..3c4cb411defa
--- /dev/null
+++ b/test/asan/TestCases/Helpers/initialization-bug-extra.cc
@@ -0,0 +1,5 @@
+// This file simply declares a dynamically initialized var by the name of 'y'.
+int initY() {
+ return 5;
+}
+int y = initY();
diff --git a/test/asan/TestCases/Helpers/initialization-bug-extra2.cc b/test/asan/TestCases/Helpers/initialization-bug-extra2.cc
new file mode 100644
index 000000000000..a3d8f190e58b
--- /dev/null
+++ b/test/asan/TestCases/Helpers/initialization-bug-extra2.cc
@@ -0,0 +1,6 @@
+// 'z' is dynamically initialized global from different TU.
+extern int z;
+int __attribute__((noinline)) initY() {
+ return z + 1;
+}
+int y = initY();
diff --git a/test/asan/TestCases/Helpers/initialization-constexpr-extra.cc b/test/asan/TestCases/Helpers/initialization-constexpr-extra.cc
new file mode 100644
index 000000000000..b32466a981b3
--- /dev/null
+++ b/test/asan/TestCases/Helpers/initialization-constexpr-extra.cc
@@ -0,0 +1,3 @@
+// Constexpr:
+int getCoolestInteger();
+static int coolest_integer = getCoolestInteger();
diff --git a/test/asan/TestCases/Helpers/initialization-nobug-extra.cc b/test/asan/TestCases/Helpers/initialization-nobug-extra.cc
new file mode 100644
index 000000000000..886165affd76
--- /dev/null
+++ b/test/asan/TestCases/Helpers/initialization-nobug-extra.cc
@@ -0,0 +1,9 @@
+// Linker initialized:
+int getAB();
+static int ab = getAB();
+// Function local statics:
+int countCalls();
+static int one = countCalls();
+// Trivial constructor, non-trivial destructor:
+int getStructWithDtorValue();
+static int val = getStructWithDtorValue();
diff --git a/test/asan/TestCases/Helpers/lit.local.cfg b/test/asan/TestCases/Helpers/lit.local.cfg
new file mode 100644
index 000000000000..2fc4d99456b0
--- /dev/null
+++ b/test/asan/TestCases/Helpers/lit.local.cfg
@@ -0,0 +1,3 @@
+# Sources in this directory are helper files for tests which test functionality
+# involving multiple translation units.
+config.suffixes = []
diff --git a/test/asan/TestCases/Linux/asan-asm-stacktrace-test.cc b/test/asan/TestCases/Linux/asan-asm-stacktrace-test.cc
new file mode 100644
index 000000000000..5332c992a0db
--- /dev/null
+++ b/test/asan/TestCases/Linux/asan-asm-stacktrace-test.cc
@@ -0,0 +1,33 @@
+// Check that a stack unwinding algorithm works corretly even with the assembly
+// instrumentation.
+
+// REQUIRES: x86_64-supported-target
+// 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
+
+#include <cstddef>
+
+// CHECK: READ of size 4
+// CHECK-NEXT: {{#0 0x[0-9a-fA-F]+ in foo}}
+// CHECK-NEXT: {{#1 0x[0-9a-fA-F]+ in main}}
+
+// CHECK-nounwind: READ of size 4
+// CHECK-nounwind-NEXT: {{#0 0x[0-9a-fA-F]+ in foo}}
+
+__attribute__((noinline)) int foo(size_t n, int *buffer) {
+ int r;
+ __asm__("movl (%[buffer], %[n], 4), %[r] \n\t"
+ : [r] "=r"(r)
+ : [buffer] "r"(buffer), [n] "r"(n)
+ : "memory");
+ return r;
+}
+
+int main() {
+ const size_t n = 16;
+ int *buffer = new int[n];
+ foo(n, buffer);
+ delete[] buffer;
+ return 0;
+}
diff --git a/test/asan/TestCases/Linux/asan_dlopen_test.cc b/test/asan/TestCases/Linux/asan_dlopen_test.cc
new file mode 100644
index 000000000000..f1e31b0a0553
--- /dev/null
+++ b/test/asan/TestCases/Linux/asan_dlopen_test.cc
@@ -0,0 +1,15 @@
+// Test that dlopen of dynamic runtime is prohibited.
+//
+// RUN: %clangxx %s -DRT=\"%shared_libasan\" -o %t -ldl
+// RUN: not %run %t 2>&1 | FileCheck %s
+// REQUIRES: asan-dynamic-runtime
+// XFAIL: android
+
+#include <dlfcn.h>
+
+int main(int argc, char **argv) {
+ dlopen(RT, RTLD_LAZY);
+ return 0;
+}
+
+// CHECK: ASan runtime does not come first in initial library list
diff --git a/test/asan/TestCases/Linux/asan_prelink_test.cc b/test/asan/TestCases/Linux/asan_prelink_test.cc
new file mode 100644
index 000000000000..6145c01f7342
--- /dev/null
+++ b/test/asan/TestCases/Linux/asan_prelink_test.cc
@@ -0,0 +1,29 @@
+// Test if asan works with prelink.
+// It does not actually use prelink, but relies on ld's flag -Ttext-segment
+// or gold's flag -Ttext (we try the first flag first, if that fails we
+// try the second flag).
+//
+// RUN: %clangxx_asan -c %s -o %t.o
+// RUN: %clangxx_asan -DBUILD_SO=1 -fPIC -shared %s -o %t.so -Wl,-Ttext-segment=0x3600000000 ||\
+// RUN: %clangxx_asan -DBUILD_SO=1 -fPIC -shared %s -o %t.so -Wl,-Ttext=0x3600000000
+// RUN: %clangxx_asan %t.o %t.so -Wl,-R. -o %t
+// RUN: ASAN_OPTIONS=verbosity=1 %run %t 2>&1 | FileCheck %s
+
+// GNU driver doesn't handle .so files properly.
+// REQUIRES: x86_64-supported-target, asan-64-bits, Clang
+#if BUILD_SO
+int G;
+int *getG() {
+ return &G;
+}
+#else
+#include <stdio.h>
+extern int *getG();
+int main(int argc, char **argv) {
+ long p = (long)getG();
+ printf("SO mapped at %lx\n", p & ~0xffffffffUL);
+ *getG() = 0;
+}
+#endif
+// CHECK: 0x003000000000, 0x004fffffffff{{.*}} MidMem
+// CHECK: SO mapped at 3600000000
diff --git a/test/asan/TestCases/Linux/asan_preload_test-1.cc b/test/asan/TestCases/Linux/asan_preload_test-1.cc
new file mode 100644
index 000000000000..e5eab5545b83
--- /dev/null
+++ b/test/asan/TestCases/Linux/asan_preload_test-1.cc
@@ -0,0 +1,30 @@
+// Test that non-sanitized executables work with sanitized shared libs
+// and preloaded runtime.
+//
+// RUN: %clangxx -DBUILD_SO=1 -fPIC -shared %s -o %t.so
+// RUN: %clangxx %s %t.so -o %t
+//
+// RUN: %clangxx_asan -DBUILD_SO=1 -fPIC -shared %s -o %t.so
+// RUN: LD_PRELOAD=%shared_libasan not %run %t 2>&1 | FileCheck %s
+
+// REQUIRES: asan-dynamic-runtime
+
+// This way of setting LD_PRELOAD does not work with Android test runner.
+// REQUIRES: not-android
+
+#if BUILD_SO
+char dummy;
+void do_access(const void *p) {
+ // CHECK: AddressSanitizer: heap-buffer-overflow
+ dummy = ((const char *)p)[1];
+}
+#else
+#include <stdlib.h>
+extern void do_access(const void *p);
+int main(int argc, char **argv) {
+ void *p = malloc(1);
+ do_access(p);
+ free(p);
+ return 0;
+}
+#endif
diff --git a/test/asan/TestCases/Linux/asan_preload_test-2.cc b/test/asan/TestCases/Linux/asan_preload_test-2.cc
new file mode 100644
index 000000000000..00b32e15d17d
--- /dev/null
+++ b/test/asan/TestCases/Linux/asan_preload_test-2.cc
@@ -0,0 +1,24 @@
+// Test that preloaded runtime works with unsanitized executables.
+//
+// RUN: %clangxx %s -o %t
+// RUN: LD_PRELOAD=%shared_libasan not %run %t 2>&1 | FileCheck %s
+
+// REQUIRES: asan-dynamic-runtime
+
+// This way of setting LD_PRELOAD does not work with Android test runner.
+// REQUIRES: not-android
+
+#include <stdlib.h>
+
+extern "C" void *memset(void *p, int val, size_t n);
+
+void do_access(void *p) {
+ // CHECK: AddressSanitizer: heap-buffer-overflow
+ memset(p, 0, 2);
+}
+
+int main(int argc, char **argv) {
+ void *p = malloc(1);
+ do_access(p);
+ return 0;
+}
diff --git a/test/asan/TestCases/Linux/asan_rt_confict_test-1.cc b/test/asan/TestCases/Linux/asan_rt_confict_test-1.cc
new file mode 100644
index 000000000000..30f1c17700c8
--- /dev/null
+++ b/test/asan/TestCases/Linux/asan_rt_confict_test-1.cc
@@ -0,0 +1,13 @@
+// Test that preloading dynamic runtime to statically sanitized
+// executable is prohibited.
+//
+// RUN: %clangxx_asan_static %s -o %t
+// RUN: LD_PRELOAD=%shared_libasan not %run %t 2>&1 | FileCheck %s
+
+// REQUIRES: asan-dynamic-runtime
+// XFAIL: android
+
+#include <stdlib.h>
+int main(int argc, char **argv) { return 0; }
+
+// CHECK: Your application is linked against incompatible ASan runtimes
diff --git a/test/asan/TestCases/Linux/asan_rt_confict_test-2.cc b/test/asan/TestCases/Linux/asan_rt_confict_test-2.cc
new file mode 100644
index 000000000000..4c935e2b0f3b
--- /dev/null
+++ b/test/asan/TestCases/Linux/asan_rt_confict_test-2.cc
@@ -0,0 +1,25 @@
+// Test that mixed static/dynamic sanitization of program objects
+// is prohibited.
+//
+// RUN: %clangxx_asan -DBUILD_SO=1 -fPIC -shared %s -o %t.so
+// RUN: %clangxx_asan_static %s %t.so -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+// REQUIRES: asan-dynamic-runtime
+// XFAIL: android
+
+#if BUILD_SO
+char dummy;
+void do_access(const void *p) { dummy = ((const char *)p)[1]; }
+#else
+#include <stdlib.h>
+extern void do_access(const void *p);
+int main(int argc, char **argv) {
+ void *p = malloc(1);
+ do_access(p);
+ free(p);
+ return 0;
+}
+#endif
+
+// CHECK: Your application is linked against incompatible ASan runtimes
diff --git a/test/asan/TestCases/Linux/clang_gcc_abi.cc b/test/asan/TestCases/Linux/clang_gcc_abi.cc
new file mode 100644
index 000000000000..e833881661d2
--- /dev/null
+++ b/test/asan/TestCases/Linux/clang_gcc_abi.cc
@@ -0,0 +1,44 @@
+// RUN: %clangxx_asan -O0 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s
+// 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
+// XFAIL: armv7l-unknown-linux-gnueabihf
+
+#include <stdlib.h>
+
+int boom() {
+ volatile int three = 3;
+ char *s = (char *)malloc(three);
+// CHECK: #1 0x{{.*}} in boom {{.*}}clang_gcc_abi.cc:[[@LINE-1]]
+ return s[three]; //BOOM
+}
+
+__attribute__((naked, noinline)) void gcc_abi() {
+// CHECK: #2 0x{{.*}} in gcc_abi {{.*}}clang_gcc_abi.cc:[[@LINE+1]]
+ asm volatile("str fp, [sp, #-8]!\n\t"
+ "str lr, [sp, #4]\n\t"
+ "add fp, sp, #4\n\t"
+ "bl boom\n\t"
+ "sub sp, fp, #4\n\t"
+ "ldr fp, [sp]\n\t"
+ "add sp, sp, #4\n\t"
+ "ldr pc, [sp], #4\n\t"
+ );
+}
+
+__attribute__((naked, noinline)) void clang_abi() {
+// CHECK: #3 0x{{.*}} in clang_abi {{.*}}clang_gcc_abi.cc:[[@LINE+1]]
+ asm volatile("push {r11, lr}\n\t"
+ "mov r11, sp\n\t"
+ "bl gcc_abi\n\t"
+ "add r0, r0, #1\n\t"
+ "pop {r11, pc}\n\t"
+ );
+}
+
+int main() {
+ clang_abi();
+// CHECK: #4 0x{{.*}} in main {{.*}}clang_gcc_abi.cc:[[@LINE-1]]
+}
diff --git a/test/asan/TestCases/Linux/clone_test.cc b/test/asan/TestCases/Linux/clone_test.cc
new file mode 100644
index 000000000000..e9c1f166eb45
--- /dev/null
+++ b/test/asan/TestCases/Linux/clone_test.cc
@@ -0,0 +1,45 @@
+// Regression test for:
+// http://code.google.com/p/address-sanitizer/issues/detail?id=37
+
+// RUN: %clangxx_asan -O0 %s -o %t && %run %t | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && %run %t | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && %run %t | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && %run %t | FileCheck %s
+// XFAIL: arm-linux-gnueabi
+
+#include <stdio.h>
+#include <sched.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+int Child(void *arg) {
+ char x[32] = {0}; // Stack gets poisoned.
+ printf("Child: %p\n", x);
+ _exit(1); // NoReturn, stack will remain unpoisoned unless we do something.
+}
+
+int main(int argc, char **argv) {
+ const int kStackSize = 1 << 20;
+ char child_stack[kStackSize + 1];
+ char *sp = child_stack + kStackSize; // Stack grows down.
+ printf("Parent: %p\n", sp);
+ pid_t clone_pid = clone(Child, sp, CLONE_FILES | CLONE_VM, NULL);
+ int status;
+ pid_t wait_result = waitpid(clone_pid, &status, __WCLONE);
+ if (wait_result < 0) {
+ perror("waitpid");
+ return 0;
+ }
+ if (wait_result == clone_pid && WIFEXITED(status)) {
+ // Make sure the child stack was indeed unpoisoned.
+ for (int i = 0; i < kStackSize; i++)
+ child_stack[i] = i;
+ int ret = child_stack[argc - 1];
+ printf("PASSED\n");
+ // CHECK: PASSED
+ return ret;
+ }
+ return 0;
+}
diff --git a/test/asan/TestCases/Linux/coverage-and-lsan.cc b/test/asan/TestCases/Linux/coverage-and-lsan.cc
new file mode 100644
index 000000000000..4cb8e2af3084
--- /dev/null
+++ b/test/asan/TestCases/Linux/coverage-and-lsan.cc
@@ -0,0 +1,20 @@
+// Make sure coverage is dumped even if there are reported leaks.
+//
+// RUN: %clangxx_asan -fsanitize-coverage=1 %s -o %t
+//
+// RUN: rm -rf %T/coverage-and-lsan
+//
+// RUN: mkdir -p %T/coverage-and-lsan/normal
+// RUN: ASAN_OPTIONS=coverage=1:coverage_dir=%T/coverage-and-lsan:verbosity=1 not %run %t 2>&1 | FileCheck %s
+// RUN: %sancov print %T/coverage-and-lsan/*.sancov 2>&1
+//
+// REQUIRES: leak-detection
+
+int *g = new int;
+int main(int argc, char **argv) {
+ g = 0;
+ return 0;
+}
+
+// CHECK: LeakSanitizer: detected memory leaks
+// CHECK: CovDump:
diff --git a/test/asan/TestCases/Linux/coverage-caller-callee-total-count.cc b/test/asan/TestCases/Linux/coverage-caller-callee-total-count.cc
new file mode 100644
index 000000000000..0201425106f9
--- /dev/null
+++ b/test/asan/TestCases/Linux/coverage-caller-callee-total-count.cc
@@ -0,0 +1,41 @@
+// Test __sanitizer_get_total_unique_coverage for caller-callee coverage
+
+// RUN: %clangxx_asan -fsanitize-coverage=4 %s -o %t
+// RUN: ASAN_OPTIONS=coverage=1 %run %t
+// RUN: rm -f caller-callee*.sancov
+//
+// REQUIRES: asan-64-bits
+
+#include <sanitizer/common_interface_defs.h>
+#include <stdio.h>
+#include <assert.h>
+int P = 0;
+struct Foo {virtual void f() {if (P) printf("Foo::f()\n");}};
+struct Foo1 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo2 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+
+Foo *foo[3] = {new Foo, new Foo1, new Foo2};
+
+uintptr_t CheckNewTotalUniqueCoverageIsLargerAndReturnIt(uintptr_t old_total) {
+ uintptr_t new_total = __sanitizer_get_total_unique_coverage();
+ assert(new_total > old_total);
+ return new_total;
+}
+
+int main(int argc, char **argv) {
+ uintptr_t total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(0);
+ foo[0]->f();
+ total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total);
+ foo[1]->f();
+ total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total);
+ foo[2]->f();
+ total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total);
+ // Ok, called every function once.
+ // Now call them again from another call site. Should get new coverage.
+ foo[0]->f();
+ total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total);
+ foo[1]->f();
+ total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total);
+ foo[2]->f();
+ total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total);
+}
diff --git a/test/asan/TestCases/Linux/coverage-caller-callee.cc b/test/asan/TestCases/Linux/coverage-caller-callee.cc
new file mode 100644
index 000000000000..cd318962b8e0
--- /dev/null
+++ b/test/asan/TestCases/Linux/coverage-caller-callee.cc
@@ -0,0 +1,74 @@
+// Test caller-callee coverage with large number of threads
+// and various numbers of callers and callees.
+
+// RUN: %clangxx_asan -fsanitize-coverage=4 %s -o %t
+// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 10 1 2>&1 | FileCheck %s --check-prefix=CHECK-10-1
+// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 9 2 2>&1 | FileCheck %s --check-prefix=CHECK-9-2
+// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 7 3 2>&1 | FileCheck %s --check-prefix=CHECK-7-3
+// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 17 1 2>&1 | FileCheck %s --check-prefix=CHECK-17-1
+// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 15 2 2>&1 | FileCheck %s --check-prefix=CHECK-15-2
+// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 18 3 2>&1 | FileCheck %s --check-prefix=CHECK-18-3
+// RUN: rm -f caller-callee*.sancov
+//
+// REQUIRES: asan-64-bits
+//
+// CHECK-10-1: CovDump: 10 caller-callee pairs written
+// CHECK-9-2: CovDump: 18 caller-callee pairs written
+// CHECK-7-3: CovDump: 21 caller-callee pairs written
+// CHECK-17-1: CovDump: 14 caller-callee pairs written
+// CHECK-15-2: CovDump: 28 caller-callee pairs written
+// CHECK-18-3: CovDump: 42 caller-callee pairs written
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+int P = 0;
+struct Foo {virtual void f() {if (P) printf("Foo::f()\n");}};
+struct Foo1 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo2 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo3 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo4 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo5 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo6 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo7 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo8 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo9 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo10 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo11 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo12 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo13 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo14 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo15 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo16 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo17 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo18 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+struct Foo19 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}};
+
+Foo *foo[20] = {
+ new Foo, new Foo1, new Foo2, new Foo3, new Foo4, new Foo5, new Foo6,
+ new Foo7, new Foo8, new Foo9, new Foo10, new Foo11, new Foo12, new Foo13,
+ new Foo14, new Foo15, new Foo16, new Foo17, new Foo18, new Foo19,
+};
+
+int n_functions = 10;
+int n_callers = 2;
+
+void *Thread(void *arg) {
+ if (n_callers >= 1) for (int i = 0; i < 2000; i++) foo[i % n_functions]->f();
+ if (n_callers >= 2) for (int i = 0; i < 2000; i++) foo[i % n_functions]->f();
+ if (n_callers >= 3) for (int i = 0; i < 2000; i++) foo[i % n_functions]->f();
+ return arg;
+}
+
+int main(int argc, char **argv) {
+ if (argc >= 2)
+ n_functions = atoi(argv[1]);
+ if (argc >= 3)
+ n_callers = atoi(argv[2]);
+ const int kNumThreads = 16;
+ pthread_t t[kNumThreads];
+ for (int i = 0; i < kNumThreads; i++)
+ pthread_create(&t[i], 0, Thread, 0);
+ for (int i = 0; i < kNumThreads; i++)
+ pthread_join(t[i], 0);
+}
diff --git a/test/asan/TestCases/Linux/coverage-direct-large.cc b/test/asan/TestCases/Linux/coverage-direct-large.cc
new file mode 100644
index 000000000000..78aa68621ad1
--- /dev/null
+++ b/test/asan/TestCases/Linux/coverage-direct-large.cc
@@ -0,0 +1,45 @@
+// Test for direct coverage writing with lots of data.
+// Current implementation maps output file in chunks of 64K. This test overflows
+// 1 chunk.
+// RUN: %clangxx_asan -fsanitize-coverage=1 -O0 %s -o %t
+
+// RUN: rm -rf %T/coverage-direct-large
+
+// RUN: mkdir -p %T/coverage-direct-large/normal && cd %T/coverage-direct-large/normal
+// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=0:verbosity=1 %run %t
+// RUN: %sancov print *.sancov >out.txt
+// RUN: cd ../..
+
+// RUN: mkdir -p %T/coverage-direct-large/direct && cd %T/coverage-direct-large/direct
+// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=1:verbosity=1 %run %t
+// RUN: %sancov rawunpack *.sancov.raw
+// RUN: %sancov print *.sancov >out.txt
+// RUN: cd ../..
+
+// RUN: diff -u coverage-direct-large/normal/out.txt coverage-direct-large/direct/out.txt
+//
+// XFAIL: android
+
+#define F0(Q, x) Q(x)
+#define F1(Q, x) \
+ F0(Q, x##0) F0(Q, x##1) F0(Q, x##2) F0(Q, x##3) F0(Q, x##4) F0(Q, x##5) \
+ F0(Q, x##6) F0(Q, x##7) F0(Q, x##8) F0(Q, x##9)
+#define F2(Q, x) \
+ F1(Q, x##0) F1(Q, x##1) F1(Q, x##2) F1(Q, x##3) F1(Q, x##4) F1(Q, x##5) \
+ F1(Q, x##6) F1(Q, x##7) F1(Q, x##8) F1(Q, x##9)
+#define F3(Q, x) \
+ F2(Q, x##0) F2(Q, x##1) F2(Q, x##2) F2(Q, x##3) F2(Q, x##4) F2(Q, x##5) \
+ F2(Q, x##6) F2(Q, x##7) F2(Q, x##8) F2(Q, x##9)
+#define F4(Q, x) \
+ F3(Q, x##0) F3(Q, x##1) F3(Q, x##2) F3(Q, x##3) F3(Q, x##4) F3(Q, x##5) \
+ F3(Q, x##6) F3(Q, x##7) F3(Q, x##8) F3(Q, x##9)
+
+#define DECL(x) __attribute__((noinline)) void x() {}
+#define CALL(x) x();
+
+F4(DECL, f)
+
+int main(void) {
+ F4(CALL, f)
+ return 0;
+}
diff --git a/test/asan/TestCases/Linux/coverage-direct.cc b/test/asan/TestCases/Linux/coverage-direct.cc
new file mode 100644
index 000000000000..2cc1aed0a0fa
--- /dev/null
+++ b/test/asan/TestCases/Linux/coverage-direct.cc
@@ -0,0 +1,44 @@
+// Test for direct coverage writing with dlopen.
+// RUN: %clangxx_asan -fsanitize-coverage=1 -DSHARED %s -shared -o %T/libcoverage_direct_test_1.so -fPIC
+// RUN: %clangxx_asan -fsanitize-coverage=1 -DSO_DIR=\"%T\" %s -o %t
+
+// RUN: rm -rf %T/coverage-direct
+
+// RUN: mkdir -p %T/coverage-direct/normal
+// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=0:coverage_dir=%T/coverage-direct/normal:verbosity=1 %run %t
+// RUN: %sancov print %T/coverage-direct/normal/*.sancov >%T/coverage-direct/normal/out.txt
+
+// RUN: mkdir -p %T/coverage-direct/direct
+// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=1:coverage_dir=%T/coverage-direct/direct:verbosity=1 %run %t
+// RUN: cd %T/coverage-direct/direct
+// RUN: %sancov rawunpack *.sancov.raw
+// RUN: %sancov print *.sancov >out.txt
+// RUN: cd ../..
+
+// RUN: diff -u coverage-direct/normal/out.txt coverage-direct/direct/out.txt
+//
+// XFAIL: android
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#ifdef SHARED
+extern "C" {
+void bar() { printf("bar\n"); }
+}
+#else
+
+int main(int argc, char **argv) {
+ fprintf(stderr, "PID: %d\n", getpid());
+ void *handle1 =
+ dlopen(SO_DIR "/libcoverage_direct_test_1.so", RTLD_LAZY);
+ assert(handle1);
+ void (*bar1)() = (void (*)())dlsym(handle1, "bar");
+ assert(bar1);
+ bar1();
+
+ return 0;
+}
+#endif
diff --git a/test/asan/TestCases/Linux/coverage-disabled.cc b/test/asan/TestCases/Linux/coverage-disabled.cc
new file mode 100644
index 000000000000..a75b26dc02e9
--- /dev/null
+++ b/test/asan/TestCases/Linux/coverage-disabled.cc
@@ -0,0 +1,18 @@
+// Test that no data is collected without a runtime flag.
+//
+// RUN: %clangxx_asan -fsanitize-coverage=1 %s -o %t
+//
+// RUN: rm -rf %T/coverage-disabled
+//
+// RUN: mkdir -p %T/coverage-disabled/normal
+// RUN: ASAN_OPTIONS=coverage_direct=0:coverage_dir=%T/coverage-disabled/normal:verbosity=1 %run %t
+// RUN: not %sancov print %T/coverage-disabled/normal/*.sancov 2>&1
+//
+// RUN: mkdir -p %T/coverage-disabled/direct
+// RUN: ASAN_OPTIONS=coverage_direct=1:coverage_dir=%T/coverage-disabled/direct:verbosity=1 %run %t
+// RUN: cd %T/coverage-disabled/direct
+// RUN: not %sancov rawunpack *.sancov
+
+int main(int argc, char **argv) {
+ return 0;
+}
diff --git a/test/asan/TestCases/Linux/coverage-fork-direct.cc b/test/asan/TestCases/Linux/coverage-fork-direct.cc
new file mode 100644
index 000000000000..51cbbd821b8e
--- /dev/null
+++ b/test/asan/TestCases/Linux/coverage-fork-direct.cc
@@ -0,0 +1,38 @@
+// RUN: %clangxx_asan -fsanitize-coverage=1 %s -o %t
+// RUN: rm -rf %T/coverage-fork-direct
+// RUN: mkdir -p %T/coverage-fork-direct && cd %T/coverage-fork-direct
+// RUN: (ASAN_OPTIONS=coverage=1:coverage_direct=1:verbosity=1 %run %t; \
+// RUN: %sancov rawunpack *.sancov.raw; %sancov print *.sancov) 2>&1
+//
+// XFAIL: android
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+__attribute__((noinline))
+void foo() { printf("foo\n"); }
+
+__attribute__((noinline))
+void bar() { printf("bar\n"); }
+
+__attribute__((noinline))
+void baz() { printf("baz\n"); }
+
+int main(int argc, char **argv) {
+ pid_t child_pid = fork();
+ if (child_pid == 0) {
+ fprintf(stderr, "Child PID: %d\n", getpid());
+ baz();
+ } else {
+ fprintf(stderr, "Parent PID: %d\n", getpid());
+ foo();
+ bar();
+ }
+ return 0;
+}
+
+// CHECK-DAG: Child PID: [[ChildPID:[0-9]+]]
+// CHECK-DAG: Parent PID: [[ParentPID:[0-9]+]]
+// CHECK-DAG: read 3 PCs from {{.*}}.[[ParentPID]].sancov
+// CHECK-DAG: read 1 PCs from {{.*}}.[[ChildPID]].sancov
diff --git a/test/asan/TestCases/Linux/coverage-fork.cc b/test/asan/TestCases/Linux/coverage-fork.cc
new file mode 100644
index 000000000000..38c200942609
--- /dev/null
+++ b/test/asan/TestCases/Linux/coverage-fork.cc
@@ -0,0 +1,38 @@
+// RUN: %clangxx_asan -fsanitize-coverage=1 %s -o %t
+// RUN: export ASAN_OPTIONS=coverage=1:coverage_direct=0:verbosity=1
+// RUN: rm -rf %T/coverage-fork
+// RUN: mkdir -p %T/coverage-fork && cd %T/coverage-fork
+// RUN: %run %t 2>&1 | FileCheck %s
+//
+// XFAIL: android
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+__attribute__((noinline))
+void foo() { printf("foo\n"); }
+
+__attribute__((noinline))
+void bar() { printf("bar\n"); }
+
+__attribute__((noinline))
+void baz() { printf("baz\n"); }
+
+int main(int argc, char **argv) {
+ pid_t child_pid = fork();
+ if (child_pid == 0) {
+ fprintf(stderr, "Child PID: %d\n", getpid());
+ baz();
+ } else {
+ fprintf(stderr, "Parent PID: %d\n", getpid());
+ foo();
+ bar();
+ }
+ return 0;
+}
+
+// CHECK-DAG: Child PID: [[ChildPID:[0-9]+]]
+// CHECK-DAG: [[ChildPID]].sancov: 1 PCs written
+// CHECK-DAG: Parent PID: [[ParentPID:[0-9]+]]
+// CHECK-DAG: [[ParentPID]].sancov: 3 PCs written
diff --git a/test/asan/TestCases/Linux/coverage-levels.cc b/test/asan/TestCases/Linux/coverage-levels.cc
new file mode 100644
index 000000000000..748ef1f08db5
--- /dev/null
+++ b/test/asan/TestCases/Linux/coverage-levels.cc
@@ -0,0 +1,20 @@
+// Test various levels of coverage
+//
+// RUN: %clangxx_asan -O1 -fsanitize-coverage=1 %s -o %t
+// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1
+// RUN: %clangxx_asan -O1 -fsanitize-coverage=2 %s -o %t
+// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2
+// RUN: %clangxx_asan -O1 -fsanitize-coverage=3 %s -o %t
+// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3
+//
+// REQUIRES: asan-64-bits
+
+volatile int sink;
+int main(int argc, char **argv) {
+ if (argc == 0)
+ sink = 0;
+}
+
+// CHECK1: 1 PCs written
+// CHECK2: 2 PCs written
+// CHECK3: 3 PCs written
diff --git a/test/asan/TestCases/Linux/coverage-maybe-open-file.cc b/test/asan/TestCases/Linux/coverage-maybe-open-file.cc
new file mode 100644
index 000000000000..4664cef7f5af
--- /dev/null
+++ b/test/asan/TestCases/Linux/coverage-maybe-open-file.cc
@@ -0,0 +1,31 @@
+// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316
+// XFAIL: android
+//
+// RUN: %clangxx_asan -fsanitize-coverage=1 %s -o %t
+// RUN: rm -rf %T/coverage-maybe-open-file
+// RUN: mkdir -p %T/coverage-maybe-open-file && cd %T/coverage-maybe-open-file
+// RUN: ASAN_OPTIONS=coverage=1 %run %t | FileCheck %s --check-prefix=CHECK-success
+// RUN: ASAN_OPTIONS=coverage=0 %run %t | FileCheck %s --check-prefix=CHECK-fail
+// RUN: [ "$(cat test.sancov.packed)" == "test" ]
+// RUN: cd .. && rm -rf %T/coverage-maybe-open-file
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sanitizer/common_interface_defs.h>
+
+int main(int argc, char **argv) {
+ int fd = __sanitizer_maybe_open_cov_file("test");
+ if (fd > 0) {
+ printf("SUCCESS\n");
+ const char s[] = "test\n";
+ write(fd, s, strlen(s));
+ close(fd);
+ } else {
+ printf("FAIL\n");
+ }
+}
+
+// CHECK-success: SUCCESS
+// CHECK-fail: FAIL
diff --git a/test/asan/TestCases/Linux/coverage-module-unloaded.cc b/test/asan/TestCases/Linux/coverage-module-unloaded.cc
new file mode 100644
index 000000000000..449841e78189
--- /dev/null
+++ b/test/asan/TestCases/Linux/coverage-module-unloaded.cc
@@ -0,0 +1,56 @@
+// Check that unloading a module doesn't break coverage dumping for remaining
+// modules.
+// RUN: %clangxx_asan -fsanitize-coverage=1 -DSHARED %s -shared -o %T/libcoverage_module_unloaded_test_1.so -fPIC
+// RUN: %clangxx_asan -fsanitize-coverage=1 -DSHARED %s -shared -o %T/libcoverage_module_unloaded_test_2.so -fPIC
+// RUN: %clangxx_asan -fsanitize-coverage=1 -DSO_DIR=\"%T\" %s -o %t
+// RUN: export ASAN_OPTIONS=coverage=1:verbosity=1
+// RUN: mkdir -p %T/coverage-module-unloaded && cd %T/coverage-module-unloaded
+// RUN: %run %t 2>&1 | FileCheck %s
+// RUN: %run %t foo 2>&1 | FileCheck %s
+// RUN: cd .. && rm coverage-module-unloaded -r
+//
+// https://code.google.com/p/address-sanitizer/issues/detail?id=263
+// XFAIL: android
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#ifdef SHARED
+extern "C" {
+void bar() { printf("bar\n"); }
+}
+#else
+
+int main(int argc, char **argv) {
+ fprintf(stderr, "PID: %d\n", getpid());
+ void *handle1 =
+ dlopen(SO_DIR "/libcoverage_module_unloaded_test_1.so", RTLD_LAZY);
+ assert(handle1);
+ void (*bar1)() = (void (*)())dlsym(handle1, "bar");
+ assert(bar1);
+ bar1();
+ void *handle2 =
+ dlopen(SO_DIR "/libcoverage_module_unloaded_test_2.so", RTLD_LAZY);
+ assert(handle2);
+ void (*bar2)() = (void (*)())dlsym(handle2, "bar");
+ assert(bar2);
+ bar2();
+
+ // It matters whether the unloaded module has a higher or lower address range
+ // than the remaining one. Make sure to test both cases.
+ if (argc < 2)
+ dlclose(bar1 < bar2 ? handle1 : handle2);
+ else
+ dlclose(bar1 < bar2 ? handle2 : handle1);
+ return 0;
+}
+#endif
+
+// CHECK: PID: [[PID:[0-9]+]]
+// CHECK: [[PID]].sancov: 1 PCs written
+// CHECK: .so.[[PID]]
+// If we get coverage for both DSOs, it means the module wasn't unloaded and
+// this test is useless.
+// CHECK-NOT: .so.[[PID]]
diff --git a/test/asan/TestCases/Linux/coverage-sandboxing.cc b/test/asan/TestCases/Linux/coverage-sandboxing.cc
new file mode 100644
index 000000000000..56f9c40f4cc0
--- /dev/null
+++ b/test/asan/TestCases/Linux/coverage-sandboxing.cc
@@ -0,0 +1,85 @@
+// RUN: %clangxx_asan -fsanitize-coverage=2 -DSHARED %s -shared -o %T/libcoverage_sandboxing_test.so -fPIC
+// RUN: %clangxx_asan -fsanitize-coverage=1 %s -o %t -Wl,-R,\$ORIGIN -L%T -lcoverage_sandboxing_test
+// RUN: export ASAN_OPTIONS=coverage=1:verbosity=1
+// RUN: rm -rf %T/coverage_sandboxing_test
+// RUN: mkdir %T/coverage_sandboxing_test && cd %T/coverage_sandboxing_test
+// RUN: mkdir vanilla && cd vanilla
+// RUN: %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-vanilla
+// RUN: mkdir ../sandbox1 && cd ../sandbox1
+// RUN: %run %t a 2>&1 | FileCheck %s --check-prefix=CHECK-sandbox
+// RUN: %sancov unpack coverage_sandboxing_test.sancov.packed
+// RUN: mkdir ../sandbox2 && cd ../sandbox2
+// RUN: %run %t a b 2>&1 | FileCheck %s --check-prefix=CHECK-sandbox
+// RUN: %sancov unpack coverage_sandboxing_test.sancov.packed
+// RUN: cd ..
+// RUN: %sancov print vanilla/libcoverage_sandboxing_test.so.*.sancov > vanilla.txt
+// RUN: %sancov print sandbox1/libcoverage_sandboxing_test.so.*.sancov > sandbox1.txt
+// RUN: %sancov print sandbox2/libcoverage_sandboxing_test.so.*.sancov > sandbox2.txt
+// RUN: diff vanilla.txt sandbox1.txt
+// RUN: diff vanilla.txt sandbox2.txt
+// RUN: cd ../ && rm coverage_sandboxing_test -r
+// https://code.google.com/p/address-sanitizer/issues/detail?id=263
+// XFAIL: android
+
+#include <assert.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sanitizer/common_interface_defs.h>
+
+#define bb0(n) \
+ case n: \
+ fprintf(stderr, "foo: %d\n", n); \
+ break;
+
+#define bb1(n) bb0(n) bb0(n + 1)
+#define bb2(n) bb1(n) bb1(n + 2)
+#define bb3(n) bb2(n) bb2(n + 4)
+#define bb4(n) bb3(n) bb3(n + 8)
+#define bb5(n) bb4(n) bb4(n + 16)
+#define bb6(n) bb5(n) bb5(n + 32)
+#define bb7(n) bb6(n) bb6(n + 64)
+#define bb8(n) bb7(n) bb7(n + 128)
+
+#ifdef SHARED
+void foo(int i) {
+ switch(i) {
+ // 256 basic blocks
+ bb8(0)
+ }
+}
+#else
+extern void foo(int i);
+
+int main(int argc, char **argv) {
+ assert(argc <= 3);
+ for (int i = 0; i < 256; i++) foo(i);
+ fprintf(stderr, "PID: %d\n", getpid());
+ if (argc == 1) {
+ // Vanilla mode, dump to individual files.
+ return 0;
+ }
+ // Dump to packed file.
+ int fd = creat("coverage_sandboxing_test.sancov.packed", 0660);
+ __sanitizer_sandbox_arguments args = {0};
+ args.coverage_sandboxed = 1;
+ args.coverage_fd = fd;
+ if (argc == 2)
+ // Write to packed file, do not split into blocks.
+ args.coverage_max_block_size = 0;
+ else if (argc == 3)
+ // Write to packed file, split into blocks (as if writing to a socket).
+ args.coverage_max_block_size = 100;
+ __sanitizer_sandbox_on_notify(&args);
+ return 0;
+}
+#endif
+
+// CHECK-vanilla: PID: [[PID:[0-9]+]]
+// CHECK-vanilla: [[PID]].sancov: 1 PCs written
+// CHECK-vanilla: .so.[[PID]].sancov: 258 PCs written
+
+// CHECK-sandbox: PID: [[PID:[0-9]+]]
+// CHECK-sandbox: 258 PCs written to packed file
diff --git a/test/asan/TestCases/Linux/coverage-tracing.cc b/test/asan/TestCases/Linux/coverage-tracing.cc
new file mode 100644
index 000000000000..89ab0d283add
--- /dev/null
+++ b/test/asan/TestCases/Linux/coverage-tracing.cc
@@ -0,0 +1,22 @@
+// Test -mllvm -sanitizer-coverage-experimental-tracing
+//
+// RUN: %clangxx_asan -O1 -fsanitize-coverage=1 -mllvm -sanitizer-coverage-experimental-tracing %s -o %t
+// RUN: rm -rf %T/coverage-tracing
+// RUN: mkdir -p %T/coverage-tracing
+// RUN: ASAN_OPTIONS=coverage=1:coverage_dir=%T/coverage-tracing:verbosity=1 %run %t 1 2 3 4 2>&1 | FileCheck %s
+// RUN: rm -rf %T/coverage-tracing
+//
+// REQUIRES: asan-64-bits
+
+volatile int sink;
+int main(int argc, char **argv) {
+ volatile int i = 0;
+ do {
+ sink = 0;
+ i++;
+ } while (i < argc);
+ return 0;
+}
+
+// CHECK: CovDump: Trace: {{[3-9]}} PCs written
+// CHECK: CovDump: Trace: {{[6-9]}} Events written
diff --git a/test/asan/TestCases/Linux/coverage.cc b/test/asan/TestCases/Linux/coverage.cc
new file mode 100644
index 000000000000..f6eb0ae9285b
--- /dev/null
+++ b/test/asan/TestCases/Linux/coverage.cc
@@ -0,0 +1,71 @@
+// RUN: %clangxx_asan -fsanitize-coverage=1 -DSHARED %s -shared -o %T/libcoverage_test.so -fPIC
+// RUN: %clangxx_asan -fsanitize-coverage=1 %s -o %t -Wl,-R,\$ORIGIN -L%T -lcoverage_test
+// RUN: export ASAN_OPTIONS=coverage=1:verbosity=1
+// RUN: mkdir -p %T/coverage && cd %T/coverage
+// RUN: %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-main
+// RUN: %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-foo
+// RUN: %run %t bar 2>&1 | FileCheck %s --check-prefix=CHECK-bar
+// RUN: %run %t foo bar 2>&1 | FileCheck %s --check-prefix=CHECK-foo-bar
+// RUN: not %run %t foo bar 4 2>&1 | FileCheck %s --check-prefix=CHECK-report
+// RUN: not %run %t foo bar 4 5 2>&1 | FileCheck %s --check-prefix=CHECK-segv
+// RUN: cd .. && rm coverage -r
+//
+// https://code.google.com/p/address-sanitizer/issues/detail?id=263
+// XFAIL: android
+
+#include "sanitizer/common_interface_defs.h"
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef SHARED
+void bar() { printf("bar\n"); }
+#else
+__attribute__((noinline))
+void foo() { printf("foo\n"); }
+extern void bar();
+
+int G[4];
+
+int main(int argc, char **argv) {
+ fprintf(stderr, "PID: %d\n", getpid());
+ for (int i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "foo")) {
+ uintptr_t old_coverage = __sanitizer_get_total_unique_coverage();
+ foo();
+ uintptr_t new_coverage = __sanitizer_get_total_unique_coverage();
+ assert(new_coverage > old_coverage);
+ }
+ if (!strcmp(argv[i], "bar"))
+ bar();
+ }
+ if (argc == 5) {
+ static volatile char *zero = 0;
+ *zero = 0; // SEGV if argc == 5.
+ }
+ return G[argc]; // Buffer overflow if argc >= 4.
+}
+#endif
+
+// CHECK-main: PID: [[PID:[0-9]+]]
+// CHECK-main: [[PID]].sancov: 1 PCs written
+// CHECK-main-NOT: .so.[[PID]]
+//
+// CHECK-foo: PID: [[PID:[0-9]+]]
+// CHECK-foo: [[PID]].sancov: 2 PCs written
+// CHECK-foo-NOT: .so.[[PID]]
+//
+// CHECK-bar: PID: [[PID:[0-9]+]]
+// CHECK-bar: [[PID]].sancov: 1 PCs written
+// CHECK-bar: .so.[[PID]].sancov: 1 PCs written
+//
+// CHECK-foo-bar: PID: [[PID:[0-9]+]]
+// CHECK-foo-bar: [[PID]].sancov: 2 PCs written
+// CHECK-foo-bar: so.[[PID]].sancov: 1 PCs written
+//
+// CHECK-report: AddressSanitizer: global-buffer-overflow
+// CHECK-report: PCs written
+//
+// CHECK-segv: AddressSanitizer: SEGV
+// CHECK-segv: PCs written
diff --git a/test/asan/TestCases/Linux/function-sections-are-bad.cc b/test/asan/TestCases/Linux/function-sections-are-bad.cc
new file mode 100644
index 000000000000..15aaccbc957f
--- /dev/null
+++ b/test/asan/TestCases/Linux/function-sections-are-bad.cc
@@ -0,0 +1,41 @@
+// Check that --gc-sections does not throw away (or localize) parts of sanitizer
+// interface.
+// RUN: %clang_asan %s -Wl,--gc-sections -ldl -o %t
+// RUN: %clang_asan %s -DBUILD_SO -fPIC -o %t-so.so -shared
+// RUN: %run %t 2>&1
+
+// REQUIRES: asan-64-bits
+
+#ifndef BUILD_SO
+#include <assert.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+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);
+
+ typedef void (*F)();
+ F f = (F)dlsym(handle, "call_rtl_from_dso");
+ printf("%s\n", dlerror());
+ assert(dlerror() == 0);
+ f();
+
+ dlclose(handle);
+ return 0;
+}
+
+#else // BUILD_SO
+
+#include <sanitizer/asan_interface.h>
+extern "C" void call_rtl_from_dso() {
+ volatile int32_t x;
+ volatile int32_t y = __sanitizer_unaligned_load32((void *)&x);
+}
+
+#endif // BUILD_SO
diff --git a/test/asan/TestCases/Linux/globals-gc-sections.cc b/test/asan/TestCases/Linux/globals-gc-sections.cc
new file mode 100644
index 000000000000..72a9e9498f85
--- /dev/null
+++ b/test/asan/TestCases/Linux/globals-gc-sections.cc
@@ -0,0 +1,13 @@
+// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -ffunction-sections -mllvm -asan-globals=0
+// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -ffunction-sections -mllvm -asan-globals=1
+
+// https://code.google.com/p/address-sanitizer/issues/detail?id=260
+// XFAIL: *
+
+int undefined();
+
+int (*unused)() = undefined;
+
+int main() {
+ return 0;
+}
diff --git a/test/asan/TestCases/Linux/initialization-bug-any-order.cc b/test/asan/TestCases/Linux/initialization-bug-any-order.cc
new file mode 100644
index 000000000000..a462f4a163f1
--- /dev/null
+++ b/test/asan/TestCases/Linux/initialization-bug-any-order.cc
@@ -0,0 +1,36 @@
+// Test to make sure basic initialization order errors are caught.
+// Check that on Linux initialization order bugs are caught
+// independently on order in which we list source files (if we specify
+// strict init-order checking).
+
+// RUN: %clangxx_asan -O0 %s %p/../Helpers/initialization-bug-extra.cc -o %t
+// RUN: ASAN_OPTIONS=strict_init_order=true not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O0 %p/../Helpers/initialization-bug-extra.cc %s -o %t
+// RUN: ASAN_OPTIONS=strict_init_order=true not %run %t 2>&1 | FileCheck %s
+
+// Do not test with optimization -- the error may be optimized away.
+
+#include <cstdio>
+
+// 'y' is a dynamically initialized global residing in a different TU. This
+// dynamic initializer will read the value of 'y' before main starts. The
+// result is undefined behavior, which should be caught by initialization order
+// checking.
+extern int y;
+int __attribute__((noinline)) initX() {
+ return y + 1;
+ // CHECK: {{AddressSanitizer: initialization-order-fiasco}}
+ // CHECK: {{READ of size .* at 0x.* thread T0}}
+ // CHECK: {{#0 0x.* in .*initX.* .*initialization-bug-any-order.cc:}}[[@LINE-3]]
+ // CHECK: {{0x.* is located 0 bytes inside of global variable .*y.*}}
+}
+
+// This initializer begins our initialization order problems.
+static int x = initX();
+
+int main() {
+ // ASan should have caused an exit before main runs.
+ printf("PASS\n");
+ // CHECK-NOT: PASS
+ return 0;
+}
diff --git a/test/asan/TestCases/Linux/interception-in-shared-lib-test.cc b/test/asan/TestCases/Linux/interception-in-shared-lib-test.cc
new file mode 100644
index 000000000000..b828d5524ee0
--- /dev/null
+++ b/test/asan/TestCases/Linux/interception-in-shared-lib-test.cc
@@ -0,0 +1,32 @@
+// Check that memset() call from a shared library gets intercepted.
+// Please always keep this file in sync with
+// ../Darwin/interception-in-shared-lib-test.cc.
+
+// RUN: %clangxx_asan -O0 %s -DSHARED_LIB \
+// RUN: -shared -o %T/libinterception-in-shared-lib-test.so \
+// RUN: -fPIC
+// TODO(glider): figure out how to set rpath in a more portable way and unite
+// this test with ../Darwin/interception-in-shared-lib-test.cc.
+// RUN: %clangxx_asan -O0 %s -o %t -Wl,-R,\$ORIGIN -L%T -linterception-in-shared-lib-test && \
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <string.h>
+
+#if defined(SHARED_LIB)
+extern "C"
+void my_memset(void *p, size_t sz) {
+ memset(p, 0, sz);
+}
+#else
+extern "C" void my_memset(void *p, size_t sz);
+
+int main(int argc, char *argv[]) {
+ char buf[10];
+ my_memset(buf, 11);
+ // CHECK: {{.*ERROR: AddressSanitizer: stack-buffer-overflow}}
+ // CHECK: {{WRITE of size 11 at 0x.* thread T0}}
+ // CHECK: {{0x.* in my_memset .*interception-in-shared-lib-test.cc:19}}
+ return 0;
+}
+#endif
diff --git a/test/asan/TestCases/Linux/interception_malloc_test.cc b/test/asan/TestCases/Linux/interception_malloc_test.cc
new file mode 100644
index 000000000000..f6d6d340bd9c
--- /dev/null
+++ b/test/asan/TestCases/Linux/interception_malloc_test.cc
@@ -0,0 +1,23 @@
+// ASan interceptor can be accessed with __interceptor_ prefix.
+
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// 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
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+extern "C" void *__interceptor_malloc(size_t size);
+extern "C" void *malloc(size_t size) {
+ write(2, "malloc call\n", sizeof("malloc call\n") - 1);
+ return __interceptor_malloc(size);
+}
+
+int main() {
+ char *x = (char*)malloc(10 * sizeof(char));
+ free(x);
+ return (int)strtol(x, 0, 10);
+ // CHECK: malloc call
+ // CHECK: heap-use-after-free
+}
diff --git a/test/asan/TestCases/Linux/interception_readdir_r_test.cc b/test/asan/TestCases/Linux/interception_readdir_r_test.cc
new file mode 100644
index 000000000000..93b553c3744f
--- /dev/null
+++ b/test/asan/TestCases/Linux/interception_readdir_r_test.cc
@@ -0,0 +1,62 @@
+// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316
+// XFAIL: android
+//
+// RUN: %clangxx_asan -O0 %s -DTEMP_DIR='"'"%T"'"' -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -DTEMP_DIR='"'"%T"'"' -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -DTEMP_DIR='"'"%T"'"' -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -DTEMP_DIR='"'"%T"'"' -o %t && %run %t 2>&1 | FileCheck %s
+//
+// RUN: %clangxx_asan -O0 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <dirent.h>
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+int main() {
+ // Ensure the readdir_r interceptor doesn't erroneously mark the entire dirent
+ // as written when the end of the directory pointer is reached.
+ fputs("test1: reading the " TEMP_DIR " directory...\n", stderr);
+ DIR *d = opendir(TEMP_DIR);
+ struct dirent *result = (struct dirent *)(0xfeedbeef);
+ // We assume the temp dir for this test doesn't have crazy long file names.
+ char entry_buffer[4096];
+ memset(entry_buffer, 0xab, sizeof(entry_buffer));
+ unsigned count = 0;
+ do {
+ // Stamp the entry struct to try to trick the interceptor.
+ ((struct dirent *)entry_buffer)->d_reclen = 9999;
+ if (readdir_r(d, (struct dirent *)entry_buffer, &result) != 0)
+ abort();
+ ++count;
+ } while (result != NULL);
+ fprintf(stderr, "read %d entries\n", count);
+ closedir(d);
+ // CHECK: test1: reading the {{.*}} directory...
+ // CHECK-NOT: stack-buffer-overflow
+ // CHECK: read {{.*}} entries
+
+ // Ensure the readdir64_r interceptor doesn't have the bug either.
+ fputs("test2: reading the " TEMP_DIR " directory...\n", stderr);
+ d = opendir(TEMP_DIR);
+ struct dirent64 *result64;
+ memset(entry_buffer, 0xab, sizeof(entry_buffer));
+ count = 0;
+ do {
+ // Stamp the entry struct to try to trick the interceptor.
+ ((struct dirent64 *)entry_buffer)->d_reclen = 9999;
+ if (readdir64_r(d, (struct dirent64 *)entry_buffer, &result64) != 0)
+ abort();
+ ++count;
+ } while (result64 != NULL);
+ fprintf(stderr, "read %d entries\n", count);
+ closedir(d);
+ // CHECK: test2: reading the {{.*}} directory...
+ // CHECK-NOT: stack-buffer-overflow
+ // CHECK: read {{.*}} entries
+}
diff --git a/test/asan/TestCases/Linux/interception_test.cc b/test/asan/TestCases/Linux/interception_test.cc
new file mode 100644
index 000000000000..fb9d01cfe6d7
--- /dev/null
+++ b/test/asan/TestCases/Linux/interception_test.cc
@@ -0,0 +1,22 @@
+// ASan interceptor can be accessed with __interceptor_ prefix.
+
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// 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
+#include <stdlib.h>
+#include <stdio.h>
+
+extern "C" long __interceptor_strtol(const char *nptr, char **endptr, int base);
+extern "C" long strtol(const char *nptr, char **endptr, int base) {
+ fprintf(stderr, "my_strtol_interceptor\n");
+ return __interceptor_strtol(nptr, endptr, base);
+}
+
+int main() {
+ char *x = (char*)malloc(10 * sizeof(char));
+ free(x);
+ return (int)strtol(x, 0, 10);
+ // CHECK: my_strtol_interceptor
+ // CHECK: heap-use-after-free
+}
diff --git a/test/asan/TestCases/Linux/interface_symbols_linux.c b/test/asan/TestCases/Linux/interface_symbols_linux.c
new file mode 100644
index 000000000000..a616732ff9f8
--- /dev/null
+++ b/test/asan/TestCases/Linux/interface_symbols_linux.c
@@ -0,0 +1,35 @@
+// Check the presence of interface symbols in compiled file.
+
+// RUN: %clang_asan -O2 %s -o %t.exe
+// RUN: nm -D %t.exe | grep " T " | sed "s/.* T //" \
+// RUN: | grep "__asan_" | sed "s/___asan_/__asan_/" \
+// RUN: | sed -E "s/__asan_init_v[0-9]+/__asan_init/" \
+// RUN: | grep -v "__asan_default_options" \
+// RUN: | grep -v "__asan_stack_" \
+// RUN: | grep -v "__asan_on_error" > %t.symbols
+// RUN: cat %p/../../../../lib/asan/asan_interface_internal.h \
+// RUN: | sed "s/\/\/.*//" | sed "s/typedef.*//" \
+// RUN: | grep -v "OPTIONAL" \
+// RUN: | grep "__asan_.*(" | sed "s/.* __asan_/__asan_/;s/(.*//" \
+// RUN: > %t.interface
+// RUN: echo __asan_report_load1 >> %t.interface
+// RUN: echo __asan_report_load2 >> %t.interface
+// RUN: echo __asan_report_load4 >> %t.interface
+// RUN: echo __asan_report_load8 >> %t.interface
+// RUN: echo __asan_report_load16 >> %t.interface
+// RUN: echo __asan_report_store1 >> %t.interface
+// RUN: echo __asan_report_store2 >> %t.interface
+// RUN: echo __asan_report_store4 >> %t.interface
+// RUN: echo __asan_report_store8 >> %t.interface
+// RUN: echo __asan_report_store16 >> %t.interface
+// RUN: echo __asan_report_load_n >> %t.interface
+// RUN: echo __asan_report_store_n >> %t.interface
+// RUN: echo __asan_get_current_fake_stack >> %t.interface
+// RUN: echo __asan_addr_is_in_fake_stack >> %t.interface
+// RUN: cat %t.interface | sort -u | diff %t.symbols -
+
+// FIXME: nm -D on powerpc somewhy shows ASan interface symbols residing
+// in "initialized data section".
+// REQUIRES: x86_64-supported-target,i386-supported-target,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
new file mode 100644
index 000000000000..8dd509f84975
--- /dev/null
+++ b/test/asan/TestCases/Linux/kernel-area.cc
@@ -0,0 +1,24 @@
+// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316
+// XFAIL: android
+//
+// Test that kernel area is not sanitized on 32-bit machines.
+//
+// RUN: %clangxx_asan %s -o %t
+// RUN: ASAN_OPTIONS=verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%kernel_bits
+// RUN: ASAN_OPTIONS=verbosity=1:full_address_space=0 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%kernel_bits
+// RUN: ASAN_OPTIONS=verbosity=1:full_address_space=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-kernel-64-bits
+//
+// CHECK-kernel-32-bits: || `[0x38000000, 0xbfffffff]` || HighMem ||
+// CHECK-kernel-32-bits: || `[0x27000000, 0x37ffffff]` || HighShadow ||
+// CHECK-kernel-32-bits: || `[0x24000000, 0x26ffffff]` || ShadowGap ||
+//
+// CHECK-kernel-64-bits: || `[0x40000000, 0xffffffff]` || HighMem ||
+// CHECK-kernel-64-bits: || `[0x28000000, 0x3fffffff]` || HighShadow ||
+// CHECK-kernel-64-bits: || `[0x24000000, 0x27ffffff]` || ShadowGap ||
+//
+// REQUIRES: asan-32-bits
+
+int main() {
+ return 0;
+}
+
diff --git a/test/asan/TestCases/Linux/leak.cc b/test/asan/TestCases/Linux/leak.cc
new file mode 100644
index 000000000000..36dc6ddb8adf
--- /dev/null
+++ b/test/asan/TestCases/Linux/leak.cc
@@ -0,0 +1,16 @@
+// Minimal test for LeakSanitizer+AddressSanitizer.
+// REQUIRES: leak-detection
+//
+// RUN: %clangxx_asan %s -o %t
+// RUN: ASAN_OPTIONS=detect_leaks=1 not %run %t 2>&1 | FileCheck %s
+// RUN: ASAN_OPTIONS="" not %run %t 2>&1 | FileCheck %s
+// RUN: ASAN_OPTIONS=detect_leaks=0 %run %t
+#include <stdio.h>
+int *t;
+
+int main(int argc, char **argv) {
+ t = new int[argc - 1];
+ printf("t: %p\n", t);
+ t = 0;
+}
+// CHECK: LeakSanitizer: detected memory leaks
diff --git a/test/asan/TestCases/Linux/lit.local.cfg b/test/asan/TestCases/Linux/lit.local.cfg
new file mode 100644
index 000000000000..57271b8078a4
--- /dev/null
+++ b/test/asan/TestCases/Linux/lit.local.cfg
@@ -0,0 +1,9 @@
+def getRoot(config):
+ if not config.parent:
+ return config
+ return getRoot(config.parent)
+
+root = getRoot(config)
+
+if root.host_os not in ['Linux']:
+ config.unsupported = True
diff --git a/test/asan/TestCases/Linux/malloc-in-qsort.cc b/test/asan/TestCases/Linux/malloc-in-qsort.cc
new file mode 100644
index 000000000000..545bc7e42a17
--- /dev/null
+++ b/test/asan/TestCases/Linux/malloc-in-qsort.cc
@@ -0,0 +1,56 @@
+// RUN: %clangxx_asan -O2 %s -o %t
+// RUN: ASAN_OPTIONS=fast_unwind_on_malloc=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-FAST
+// RUN: ASAN_OPTIONS=fast_unwind_on_malloc=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-SLOW
+
+// Test how well we unwind in presence of qsort in the stack
+// (i.e. if we can unwind through a function compiled w/o frame pointers).
+// https://code.google.com/p/address-sanitizer/issues/detail?id=137
+
+// Fast unwinder is only available on x86_64 and i386.
+// REQUIRES: x86_64-supported-target
+
+// REQUIRES: compiler-rt-optimized
+
+#include <stdlib.h>
+#include <stdio.h>
+
+int *GlobalPtr;
+
+extern "C" {
+int QsortCallback(const void *a, const void *b) {
+ char *x = (char*)a;
+ char *y = (char*)b;
+ printf("Calling QsortCallback\n");
+ GlobalPtr = new int[10];
+ return (int)*x - (int)*y;
+}
+
+__attribute__((noinline))
+void MyQsort(char *a, size_t size) {
+ printf("Calling qsort\n");
+ qsort(a, size, sizeof(char), QsortCallback);
+ printf("Done\n"); // Avoid tail call.
+}
+} // extern "C"
+
+int main() {
+ char a[2] = {1, 2};
+ MyQsort(a, 2);
+ return GlobalPtr[10];
+}
+
+// Fast unwind: can not unwind through qsort.
+// FIXME: this test does not properly work with slow unwind yet.
+
+// CHECK-FAST: ERROR: AddressSanitizer: heap-buffer-overflow
+// CHECK-FAST: is located 0 bytes to the right
+// CHECK-FAST: #0{{.*}}operator new
+// CHECK-FAST-NEXT: #1{{.*}}QsortCallback
+// CHECK-FAST-NOT: MyQsort
+//
+// CHECK-SLOW: ERROR: AddressSanitizer: heap-buffer-overflow
+// CHECK-SLOW: is located 0 bytes to the right
+// CHECK-SLOW: #0{{.*}}operator new
+// CHECK-SLOW-NEXT: #1{{.*}}QsortCallback
+// CHECK-SLOW: #{{.*}}MyQsort
+// CHECK-SLOW-NEXT: #{{.*}}main
diff --git a/test/asan/TestCases/Linux/malloc_delete_mismatch.cc b/test/asan/TestCases/Linux/malloc_delete_mismatch.cc
new file mode 100644
index 000000000000..18d65ce0008f
--- /dev/null
+++ b/test/asan/TestCases/Linux/malloc_delete_mismatch.cc
@@ -0,0 +1,33 @@
+// Check that we detect malloc/delete mismatch only if the approptiate flag
+// is set.
+
+// RUN: %clangxx_asan -g %s -o %t 2>&1
+
+// Find error and provide malloc context.
+// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=ALLOC-STACK
+
+// No error here.
+// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=0 %run %t
+
+// Also works if no malloc context is available.
+// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=1:malloc_context_size=0:fast_unwind_on_malloc=0 not %run %t 2>&1 | FileCheck %s
+// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=1:malloc_context_size=0:fast_unwind_on_malloc=1 not %run %t 2>&1 | FileCheck %s
+// XFAIL: arm-linux-gnueabi
+// XFAIL: armv7l-unknown-linux-gnueabihf
+#include <stdlib.h>
+
+static volatile char *x;
+
+int main() {
+ x = (char*)malloc(10);
+ x[0] = 0;
+ delete x;
+}
+// CHECK: ERROR: AddressSanitizer: alloc-dealloc-mismatch (malloc vs operator delete) on 0x
+// CHECK-NEXT: #0{{.*}}operator delete
+// CHECK: #{{.*}}main
+// CHECK: is located 0 bytes inside of 10-byte region
+// CHECK-NEXT: allocated by thread T0 here:
+// ALLOC-STACK-NEXT: #0{{.*}}malloc
+// ALLOC-STACK: #{{.*}}main
+// CHECK: HINT: {{.*}} you may set ASAN_OPTIONS=alloc_dealloc_mismatch=0
diff --git a/test/asan/TestCases/Linux/odr-violation.cc b/test/asan/TestCases/Linux/odr-violation.cc
new file mode 100644
index 000000000000..ddc68a2db0f1
--- /dev/null
+++ b/test/asan/TestCases/Linux/odr-violation.cc
@@ -0,0 +1,42 @@
+// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316
+// XFAIL: android
+//
+// Different size: detect a bug if detect_odr_violation>=1
+// RUN: %clangxx_asan -DBUILD_SO=1 -fPIC -shared %s -o %t-ODR-SO.so
+// RUN: %clangxx_asan %s %t-ODR-SO.so -Wl,-R. -o %t-ODR-EXE
+// RUN: ASAN_OPTIONS=detect_odr_violation=1 not %run %t-ODR-EXE 2>&1 | FileCheck %s
+// RUN: ASAN_OPTIONS=detect_odr_violation=2 not %run %t-ODR-EXE 2>&1 | FileCheck %s
+// RUN: ASAN_OPTIONS=detect_odr_violation=0 %run %t-ODR-EXE 2>&1 | FileCheck %s --check-prefix=DISABLED
+// RUN: not %run %t-ODR-EXE 2>&1 | FileCheck %s
+//
+// Same size: report a bug only if detect_odr_violation>=2.
+// RUN: %clangxx_asan -DBUILD_SO=1 -fPIC -shared %s -o %t-ODR-SO.so -DSZ=100
+// RUN: ASAN_OPTIONS=detect_odr_violation=1 %run %t-ODR-EXE 2>&1 | FileCheck %s --check-prefix=DISABLED
+// RUN: ASAN_OPTIONS=detect_odr_violation=2 not %run %t-ODR-EXE 2>&1 | FileCheck %s
+// RUN: not %run %t-ODR-EXE 2>&1 | FileCheck %s
+
+// GNU driver doesn't handle .so files properly.
+// REQUIRES: Clang
+
+#ifndef SZ
+# define SZ 4
+#endif
+
+#if BUILD_SO
+namespace foo { char G[SZ]; }
+#else
+#include <stdio.h>
+namespace foo { char G[100]; }
+// CHECK: ERROR: AddressSanitizer: odr-violation
+// CHECK: size=100 'foo::G' {{.*}}odr-violation.cc:[[@LINE-2]]:22
+// CHECK: size={{4|100}} 'foo::G'
+int main(int argc, char **argv) {
+ printf("PASS: %p\n", &foo::G);
+}
+#endif
+
+// CHECK: These globals were registered at these points:
+// CHECK: ODR-EXE
+// CHECK: ODR-SO
+// CHECK: SUMMARY: AddressSanitizer: odr-violation: global 'foo::G' at {{.*}}odr-violation.cc
+// DISABLED: PASS
diff --git a/test/asan/TestCases/Linux/overflow-in-qsort.cc b/test/asan/TestCases/Linux/overflow-in-qsort.cc
new file mode 100644
index 000000000000..79b654e117cd
--- /dev/null
+++ b/test/asan/TestCases/Linux/overflow-in-qsort.cc
@@ -0,0 +1,51 @@
+// RUN: %clangxx_asan -O2 %s -o %t
+// RUN: ASAN_OPTIONS=fast_unwind_on_fatal=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-FAST
+// RUN: ASAN_OPTIONS=fast_unwind_on_fatal=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-SLOW
+
+// Test how well we unwind in presence of qsort in the stack
+// (i.e. if we can unwind through a function compiled w/o frame pointers).
+// https://code.google.com/p/address-sanitizer/issues/detail?id=137
+
+// Fast unwinder is only available on x86_64 and i386.
+// REQUIRES: x86_64-supported-target
+
+#include <stdlib.h>
+#include <stdio.h>
+
+int global_array[10];
+volatile int one = 1;
+
+extern "C" {
+int QsortCallback(const void *a, const void *b) {
+ char *x = (char*)a;
+ char *y = (char*)b;
+ printf("Calling QsortCallback\n");
+ global_array[one * 10] = 0; // BOOM
+ return (int)*x - (int)*y;
+}
+
+__attribute__((noinline))
+void MyQsort(char *a, size_t size) {
+ printf("Calling qsort\n");
+ qsort(a, size, sizeof(char), QsortCallback);
+ printf("Done\n"); // Avoid tail call.
+}
+} // extern "C"
+
+int main() {
+ char a[2] = {1, 2};
+ MyQsort(a, 2);
+}
+
+// Fast unwind: can not unwind through qsort.
+
+// CHECK-FAST: ERROR: AddressSanitizer: global-buffer-overflow
+// CHECK-FAST: #0{{.*}} in QsortCallback
+// CHECK-FAST-NOT: MyQsort
+// CHECK-FAST: is located 0 bytes to the right of global variable 'global_array
+
+// CHECK-SLOW: ERROR: AddressSanitizer: global-buffer-overflow
+// CHECK-SLOW: #0{{.*}} in QsortCallback
+// CHECK-SLOW: #{{.*}} in MyQsort
+// CHECK-SLOW: #{{.*}} in main
+// CHECK-SLOW: is located 0 bytes to the right of global variable 'global_array
diff --git a/test/asan/TestCases/Linux/preinit_test.cc b/test/asan/TestCases/Linux/preinit_test.cc
new file mode 100644
index 000000000000..10dde67d6a9b
--- /dev/null
+++ b/test/asan/TestCases/Linux/preinit_test.cc
@@ -0,0 +1,33 @@
+// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316
+// XFAIL: android
+//
+// RUN: %clangxx -DFUNC=zzzz %s -shared -o %t.so -fPIC
+// RUN: %clangxx_asan -DFUNC=main %s -o %t -Wl,-R. %t.so
+// RUN: %run %t
+
+// GNU driver doesn't handle .so files properly.
+// REQUIRES: Clang
+
+// This test ensures that we call __asan_init early enough.
+// We build a shared library w/o asan instrumentation
+// and the binary with asan instrumentation.
+// Both files include the same header (emulated by -DFUNC here)
+// with C++ template magic which runs global initializer at library load time.
+// The function get() is instrumented with asan, but called
+// before the usual constructors are run.
+// So, we must make sure that __asan_init is executed even earlier.
+//
+// See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56393
+
+struct A {
+ int foo() const { return 0; }
+};
+A get () { return A(); }
+template <class> struct O {
+ static A const e;
+};
+template <class T> A const O <T>::e = get();
+int FUNC() {
+ return O<int>::e.foo();
+}
+
diff --git a/test/asan/TestCases/Linux/ptrace.cc b/test/asan/TestCases/Linux/ptrace.cc
new file mode 100644
index 000000000000..7e5acb64c7a1
--- /dev/null
+++ b/test/asan/TestCases/Linux/ptrace.cc
@@ -0,0 +1,56 @@
+// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316
+// XFAIL: android
+//
+// RUN: %clangxx_asan -O0 %s -o %t && %run %t
+// RUN: %clangxx_asan -DPOSITIVE -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// REQUIRES: x86_64-supported-target,i386-supported-target
+
+#include <assert.h>
+#include <stdio.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+int main(void) {
+ pid_t pid;
+ pid = fork();
+ if (pid == 0) { // child
+ ptrace(PTRACE_TRACEME, 0, NULL, NULL);
+ execl("/bin/true", "true", NULL);
+ } else {
+ wait(NULL);
+ user_regs_struct regs;
+ int res;
+ user_regs_struct * volatile pregs = &regs;
+#ifdef POSITIVE
+ ++pregs;
+#endif
+ res = ptrace(PTRACE_GETREGS, pid, NULL, pregs);
+ // CHECK: AddressSanitizer: stack-buffer-overflow
+ // CHECK: {{.*ptrace.cc:}}[[@LINE-2]]
+ assert(!res);
+#if __WORDSIZE == 64
+ printf("%zx\n", regs.rip);
+#else
+ printf("%lx\n", regs.eip);
+#endif
+
+ user_fpregs_struct fpregs;
+ res = ptrace(PTRACE_GETFPREGS, pid, NULL, &fpregs);
+ assert(!res);
+ printf("%lx\n", (unsigned long)fpregs.cwd);
+
+#if __WORDSIZE == 32
+ user_fpxregs_struct fpxregs;
+ res = ptrace(PTRACE_GETFPXREGS, pid, NULL, &fpxregs);
+ assert(!res);
+ printf("%lx\n", (unsigned long)fpxregs.mxcsr);
+#endif
+
+ ptrace(PTRACE_CONT, pid, NULL, NULL);
+ wait(NULL);
+ }
+ return 0;
+}
diff --git a/test/asan/TestCases/Linux/rlimit_mmap_test.cc b/test/asan/TestCases/Linux/rlimit_mmap_test.cc
new file mode 100644
index 000000000000..7f37727b2eeb
--- /dev/null
+++ b/test/asan/TestCases/Linux/rlimit_mmap_test.cc
@@ -0,0 +1,16 @@
+// Check that we properly report mmap failure.
+// RUN: %clangxx_asan %s -o %t && not %run %t 2>&1 | FileCheck %s
+#include <stdlib.h>
+#include <assert.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+static volatile void *x;
+
+int main(int argc, char **argv) {
+ struct rlimit mmap_resource_limit = { 0, 0 };
+ assert(0 == setrlimit(RLIMIT_AS, &mmap_resource_limit));
+ x = malloc(10000000);
+// CHECK: ERROR: Failed to mmap
+ return 0;
+}
diff --git a/test/asan/TestCases/Linux/shmctl.cc b/test/asan/TestCases/Linux/shmctl.cc
new file mode 100644
index 000000000000..e1752bc894c0
--- /dev/null
+++ b/test/asan/TestCases/Linux/shmctl.cc
@@ -0,0 +1,27 @@
+// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316
+// XFAIL: android
+//
+// RUN: %clangxx_asan -O1 %s -o %t && %run %t 2>&1
+// Regression test for
+// https://code.google.com/p/address-sanitizer/issues/detail?id=250
+#include <stdio.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <assert.h>
+
+int main() {
+ int id = shmget(IPC_PRIVATE, 4096, 0644 | IPC_CREAT);
+ assert(id > -1);
+ struct shmid_ds ds;
+ int res = shmctl(id, IPC_STAT, &ds);
+ assert(res > -1);
+ printf("shm_segsz: %zd\n", ds.shm_segsz);
+ assert(ds.shm_segsz == 4096);
+ assert(-1 != shmctl(id, IPC_RMID, 0));
+
+ struct shm_info shmInfo;
+ res = shmctl(0, SHM_INFO, (struct shmid_ds *)&shmInfo);
+ assert(res > -1);
+
+ return 0;
+}
diff --git a/test/asan/TestCases/Linux/sized_delete_test.cc b/test/asan/TestCases/Linux/sized_delete_test.cc
new file mode 100644
index 000000000000..823e3c0bf88e
--- /dev/null
+++ b/test/asan/TestCases/Linux/sized_delete_test.cc
@@ -0,0 +1,93 @@
+// RUN: %clangxx_asan -Xclang -fsized-deallocation -O0 %s -o %t
+// RUN: not %run %t scalar 2>&1 | FileCheck %s -check-prefix=SCALAR
+// RUN: ASAN_OPTIONS=new_delete_type_mismatch=1 not %run %t scalar 2>&1 | FileCheck %s -check-prefix=SCALAR
+// RUN: not %run %t array 2>&1 | FileCheck %s -check-prefix=ARRAY
+// RUN: ASAN_OPTIONS=new_delete_type_mismatch=1 not %run %t array 2>&1 | FileCheck %s -check-prefix=ARRAY
+// RUN: ASAN_OPTIONS=new_delete_type_mismatch=0 %run %t scalar
+// RUN: ASAN_OPTIONS=new_delete_type_mismatch=0 %run %t array
+
+// Sized-delete is implemented with a weak delete() definition.
+// Weak symbols are kind of broken on Android.
+// XFAIL: android
+
+#include <new>
+#include <stdio.h>
+#include <string>
+
+inline void break_optimization(void *arg) {
+ __asm__ __volatile__("" : : "r" (arg) : "memory");
+}
+
+struct S12 {
+ int a, b, c;
+};
+
+struct S20 {
+ int a, b, c, d, e;
+};
+
+struct D1 {
+ int a, b, c;
+ ~D1() { fprintf(stderr, "D1::~D1\n"); }
+};
+
+struct D2 {
+ int a, b, c, d, e;
+ ~D2() { fprintf(stderr, "D2::~D2\n"); }
+};
+
+void Del12(S12 *x) {
+ break_optimization(x);
+ delete x;
+}
+void Del12NoThrow(S12 *x) {
+ break_optimization(x);
+ operator delete(x, std::nothrow);
+}
+void Del12Ar(S12 *x) {
+ break_optimization(x);
+ delete [] x;
+}
+void Del12ArNoThrow(S12 *x) {
+ break_optimization(x);
+ operator delete[](x, std::nothrow);
+}
+
+int main(int argc, char **argv) {
+ if (argc != 2) return 1;
+ std::string flag = argv[1];
+ // These are correct.
+ Del12(new S12);
+ Del12NoThrow(new S12);
+ Del12Ar(new S12[100]);
+ Del12ArNoThrow(new S12[100]);
+
+ // Here we pass wrong type of pointer to delete,
+ // but [] and nothrow variants of delete are not sized.
+ Del12Ar(reinterpret_cast<S12*>(new S20[100]));
+ Del12NoThrow(reinterpret_cast<S12*>(new S20));
+ Del12ArNoThrow(reinterpret_cast<S12*>(new S20[100]));
+ fprintf(stderr, "OK SO FAR\n");
+ // SCALAR: OK SO FAR
+ // ARRAY: OK SO FAR
+ if (flag == "scalar") {
+ // Here asan should bark as we are passing a wrong type of pointer
+ // to sized delete.
+ Del12(reinterpret_cast<S12*>(new S20));
+ // SCALAR: AddressSanitizer: new-delete-type-mismatch
+ // SCALAR: object passed to delete has wrong type:
+ // SCALAR: size of the allocated type: 20 bytes;
+ // SCALAR: size of the deallocated type: 12 bytes.
+ // SCALAR: is located 0 bytes inside of 20-byte region
+ // SCALAR: SUMMARY: AddressSanitizer: new-delete-type-mismatch
+ } else if (flag == "array") {
+ D1 *d1 = reinterpret_cast<D1*>(new D2[10]);
+ break_optimization(d1);
+ delete [] d1;
+ // ARRAY-NOT: D2::~D2
+ // ARRAY: D1::~D1
+ // ARRAY: AddressSanitizer: new-delete-type-mismatch
+ // ARRAY: size of the allocated type: 20{{4|8}} bytes;
+ // ARRAY: size of the deallocated type: 12{{4|8}} bytes.
+ }
+}
diff --git a/test/asan/TestCases/Linux/stack-trace-dlclose.cc b/test/asan/TestCases/Linux/stack-trace-dlclose.cc
new file mode 100644
index 000000000000..e494e5661d1d
--- /dev/null
+++ b/test/asan/TestCases/Linux/stack-trace-dlclose.cc
@@ -0,0 +1,45 @@
+// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316
+// XFAIL: android
+//
+// RUN: %clangxx_asan -DSHARED %s -shared -o %T/stack_trace_dlclose.so -fPIC
+// RUN: %clangxx_asan -DSO_DIR=\"%T\" %s -o %t
+// RUN: ASAN_OPTIONS=exitcode=0 %run %t 2>&1 | FileCheck %s
+// XFAIL: arm-linux-gnueabi
+// XFAIL: armv7l-unknown-linux-gnueabihf
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <sanitizer/common_interface_defs.h>
+
+#ifdef SHARED
+extern "C" {
+void *foo() {
+ return malloc(1);
+}
+}
+#else
+void *handle;
+
+int main(int argc, char **argv) {
+ void *handle = dlopen(SO_DIR "/stack_trace_dlclose.so", RTLD_LAZY);
+ assert(handle);
+ void *(*foo)() = (void *(*)())dlsym(handle, "foo");
+ assert(foo);
+ void *p = foo();
+ assert(p);
+ dlclose(handle);
+
+ free(p);
+ free(p); // double-free
+
+ return 0;
+}
+#endif
+
+// CHECK: {{ #0 0x.* in malloc}}
+// CHECK: {{ #1 0x.* \(<unknown module>\)}}
+// CHECK: {{ #2 0x.* in main}}
diff --git a/test/asan/TestCases/Linux/stress_dtls.c b/test/asan/TestCases/Linux/stress_dtls.c
new file mode 100644
index 000000000000..cb901ee59953
--- /dev/null
+++ b/test/asan/TestCases/Linux/stress_dtls.c
@@ -0,0 +1,116 @@
+// REQUIRES: asan-64-bits
+// Stress test dynamic TLS + dlopen + threads.
+//
+// Note that glibc 2.15 seems utterly broken on this test,
+// it fails with ~17 DSOs dlopen-ed.
+// glibc 2.19 seems fine.
+//
+//
+// RUN: %clangxx_asan -x c -DSO_NAME=f0 %s -shared -o %t-f0.so -fPIC
+// RUN: %clangxx_asan -x c -DSO_NAME=f1 %s -shared -o %t-f1.so -fPIC
+// RUN: %clangxx_asan -x c -DSO_NAME=f2 %s -shared -o %t-f2.so -fPIC
+// RUN: %clangxx_asan %s -ldl -pthread -o %t
+// RUN: %run %t 0 3
+// RUN: %run %t 2 3
+// RUN: ASAN_OPTIONS=verbosity=2 %run %t 10 2 2>&1 | FileCheck %s
+// RUN: ASAN_OPTIONS=verbosity=2:intercept_tls_get_addr=1 %run %t 10 2 2>&1 | FileCheck %s
+// RUN: ASAN_OPTIONS=verbosity=2:intercept_tls_get_addr=0 %run %t 10 2 2>&1 | FileCheck %s --check-prefix=CHECK0
+// CHECK: __tls_get_addr
+// CHECK: Creating thread 0
+// CHECK: __tls_get_addr
+// CHECK: Creating thread 1
+// CHECK: __tls_get_addr
+// CHECK: Creating thread 2
+// CHECK: __tls_get_addr
+// CHECK: Creating thread 3
+// CHECK: __tls_get_addr
+// Make sure that TLS slots don't leak
+// CHECK-NOT: num_live_dtls 5
+//
+// CHECK0-NOT: __tls_get_addr
+/*
+cc=your-compiler
+
+$cc stress_dtls.c -pthread -ldl
+for((i=0;i<100;i++)); do
+ $cc -fPIC -shared -DSO_NAME=f$i -o a.out-f$i.so stress_dtls.c;
+done
+./a.out 2 4 # <<<<<< 2 threads, 4 libs
+./a.out 3 50 # <<<<<< 3 threads, 50 libs
+*/
+#ifndef SO_NAME
+#define _GNU_SOURCE
+#include <assert.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <stdint.h>
+
+typedef void **(*f_t)();
+
+__thread int my_tls;
+
+#define MAX_N_FUNCTIONS 1000
+f_t Functions[MAX_N_FUNCTIONS];
+
+void *PrintStuff(void *unused) {
+ uintptr_t stack;
+ // fprintf(stderr, "STACK: %p TLS: %p SELF: %p\n", &stack, &my_tls,
+ // (void *)pthread_self());
+ int i;
+ for (i = 0; i < MAX_N_FUNCTIONS; i++) {
+ if (!Functions[i]) break;
+ uintptr_t dtls = (uintptr_t)Functions[i]();
+ fprintf(stderr, " dtls[%03d]: %lx\n", i, dtls);
+ *(long*)dtls = 42; // check that this is writable.
+ }
+ return NULL;
+}
+
+int main(int argc, char *argv[]) {
+ int num_threads = 1;
+ int num_libs = 1;
+ if (argc >= 2)
+ num_threads = atoi(argv[1]);
+ if (argc >= 3)
+ num_libs = atoi(argv[2]);
+ assert(num_libs <= MAX_N_FUNCTIONS);
+
+ int lib;
+ for (lib = 0; lib < num_libs; lib++) {
+ char buf[4096];
+ snprintf(buf, sizeof(buf), "%s-f%d.so", argv[0], lib);
+ void *handle = dlopen(buf, RTLD_LAZY);
+ if (!handle) {
+ fprintf(stderr, "%s\n", dlerror());
+ exit(1);
+ }
+ snprintf(buf, sizeof(buf), "f%d", lib);
+ Functions[lib] = (f_t)dlsym(handle, buf);
+ if (!Functions[lib]) {
+ fprintf(stderr, "%s\n", dlerror());
+ exit(1);
+ }
+ fprintf(stderr, "LIB[%03d] %s: %p\n", lib, buf, Functions[lib]);
+ PrintStuff(0);
+
+ int i;
+ for (i = 0; i < num_threads; i++) {
+ pthread_t t;
+ fprintf(stderr, "Creating thread %d\n", i);
+ pthread_create(&t, 0, PrintStuff, 0);
+ pthread_join(t, 0);
+ }
+ }
+ return 0;
+}
+#else // SO_NAME
+#ifndef DTLS_SIZE
+# define DTLS_SIZE (1 << 17)
+#endif
+__thread void *huge_thread_local_array[DTLS_SIZE];
+void **SO_NAME() {
+ return &huge_thread_local_array[0];
+}
+#endif
diff --git a/test/asan/TestCases/Linux/swapcontext_test.cc b/test/asan/TestCases/Linux/swapcontext_test.cc
new file mode 100644
index 000000000000..86ed5930bcf4
--- /dev/null
+++ b/test/asan/TestCases/Linux/swapcontext_test.cc
@@ -0,0 +1,90 @@
+// Check that ASan plays well with easy cases of makecontext/swapcontext.
+
+// RUN: %clangxx_asan -O0 %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && %run %t 2>&1 | FileCheck %s
+// 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
+
+#include <stdio.h>
+#include <ucontext.h>
+#include <unistd.h>
+
+ucontext_t orig_context;
+ucontext_t child_context;
+
+const int kStackSize = 1 << 20;
+
+__attribute__((noinline))
+void Throw() {
+ throw 1;
+}
+
+__attribute__((noinline))
+void ThrowAndCatch() {
+ try {
+ Throw();
+ } catch(int a) {
+ printf("ThrowAndCatch: %d\n", a);
+ }
+}
+
+void Child(int mode) {
+ char x[32] = {0}; // Stack gets poisoned.
+ printf("Child: %p\n", x);
+ ThrowAndCatch(); // Simulate __asan_handle_no_return().
+ // (a) Do nothing, just return to parent function.
+ // (b) Jump into the original function. Stack remains poisoned unless we do
+ // something.
+ if (mode == 1) {
+ if (swapcontext(&child_context, &orig_context) < 0) {
+ perror("swapcontext");
+ _exit(0);
+ }
+ }
+}
+
+int Run(int arg, int mode, char *child_stack) {
+ printf("Child stack: %p\n", child_stack);
+ // Setup child context.
+ getcontext(&child_context);
+ child_context.uc_stack.ss_sp = child_stack;
+ child_context.uc_stack.ss_size = kStackSize / 2;
+ if (mode == 0) {
+ child_context.uc_link = &orig_context;
+ }
+ makecontext(&child_context, (void (*)())Child, 1, mode);
+ if (swapcontext(&orig_context, &child_context) < 0) {
+ perror("swapcontext");
+ return 0;
+ }
+ // Touch childs's stack to make sure it's unpoisoned.
+ for (int i = 0; i < kStackSize; i++) {
+ child_stack[i] = i;
+ }
+ return child_stack[arg];
+}
+
+int main(int argc, char **argv) {
+ char stack[kStackSize + 1];
+ // CHECK: WARNING: ASan doesn't fully support makecontext/swapcontext
+ int ret = 0;
+ ret += Run(argc - 1, 0, stack);
+ printf("Test1 passed\n");
+ // CHECK: Test1 passed
+ ret += Run(argc - 1, 1, stack);
+ printf("Test2 passed\n");
+ // CHECK: Test2 passed
+ char *heap = new char[kStackSize + 1];
+ ret += Run(argc - 1, 0, heap);
+ printf("Test3 passed\n");
+ // CHECK: Test3 passed
+ ret += Run(argc - 1, 1, heap);
+ printf("Test4 passed\n");
+ // CHECK: Test4 passed
+
+ delete [] heap;
+ return ret;
+}
diff --git a/test/asan/TestCases/Linux/syscalls.cc b/test/asan/TestCases/Linux/syscalls.cc
new file mode 100644
index 000000000000..bcdd5bc82119
--- /dev/null
+++ b/test/asan/TestCases/Linux/syscalls.cc
@@ -0,0 +1,25 @@
+// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316
+// XFAIL: android
+//
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <errno.h>
+#include <glob.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <sanitizer/linux_syscall_hooks.h>
+
+/* Test the presence of __sanitizer_syscall_ in the tool runtime, and general
+ sanity of their behaviour. */
+
+int main(int argc, char *argv[]) {
+ char buf[1000];
+ __sanitizer_syscall_pre_recvmsg(0, buf - 1, 0);
+ // CHECK: AddressSanitizer: stack-buffer-{{.*}}erflow
+ // CHECK: READ of size {{.*}} at {{.*}} thread T0
+ // CHECK: #0 {{.*}} in __sanitizer_syscall{{.*}}recvmsg
+ return 0;
+}
diff --git a/test/asan/TestCases/Linux/uar_signals.cc b/test/asan/TestCases/Linux/uar_signals.cc
new file mode 100644
index 000000000000..f42c3f666554
--- /dev/null
+++ b/test/asan/TestCases/Linux/uar_signals.cc
@@ -0,0 +1,70 @@
+// This test checks that the implementation of use-after-return
+// is async-signal-safe.
+// RUN: %clangxx_asan -O1 %s -o %t -pthread && %run %t
+// REQUIRES: stable-runtime
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <pthread.h>
+
+int *g;
+int n_signals;
+
+typedef void (*Sigaction)(int, siginfo_t *, void *);
+
+void SignalHandler(int, siginfo_t*, void*) {
+ int local;
+ g = &local;
+ n_signals++;
+ // printf("s: %p\n", &local);
+}
+
+static void EnableSigprof(Sigaction SignalHandler) {
+ struct sigaction sa;
+ sa.sa_sigaction = SignalHandler;
+ sa.sa_flags = SA_RESTART | SA_SIGINFO;
+ sigemptyset(&sa.sa_mask);
+ if (sigaction(SIGPROF, &sa, NULL) != 0) {
+ perror("sigaction");
+ abort();
+ }
+ struct itimerval timer;
+ timer.it_interval.tv_sec = 0;
+ timer.it_interval.tv_usec = 1;
+ timer.it_value = timer.it_interval;
+ if (setitimer(ITIMER_PROF, &timer, 0) != 0) {
+ perror("setitimer");
+ abort();
+ }
+}
+
+void RecursiveFunction(int depth) {
+ if (depth == 0) return;
+ int local;
+ g = &local;
+ // printf("r: %p\n", &local);
+ // printf("[%2d] n_signals: %d\n", depth, n_signals);
+ RecursiveFunction(depth - 1);
+ RecursiveFunction(depth - 1);
+}
+
+void *Thread(void *) {
+ RecursiveFunction(18);
+ return NULL;
+}
+
+int main(int argc, char **argv) {
+ EnableSigprof(SignalHandler);
+
+ for (int i = 0; i < 4; i++) {
+ fprintf(stderr, ".");
+ const int kNumThread = sizeof(void*) == 8 ? 16 : 8;
+ pthread_t t[kNumThread];
+ for (int i = 0; i < kNumThread; i++)
+ pthread_create(&t[i], 0, Thread, 0);
+ for (int i = 0; i < kNumThread; i++)
+ pthread_join(t[i], 0);
+ }
+ fprintf(stderr, "\n");
+}
diff --git a/test/asan/TestCases/Linux/unpoison_tls.cc b/test/asan/TestCases/Linux/unpoison_tls.cc
new file mode 100644
index 000000000000..9c1d74b28e5f
--- /dev/null
+++ b/test/asan/TestCases/Linux/unpoison_tls.cc
@@ -0,0 +1,35 @@
+// Test that TLS is unpoisoned on thread death.
+// REQUIRES: x86_64-supported-target,i386-supported-target
+
+// RUN: %clangxx_asan -O1 %s -pthread -o %t && %run %t 2>&1
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+
+#include <sanitizer/asan_interface.h>
+
+__thread int64_t tls_var[2];
+
+volatile int64_t *p_tls_var;
+
+void *first(void *arg) {
+ ASAN_POISON_MEMORY_REGION(&tls_var, sizeof(tls_var));
+ p_tls_var = tls_var;
+ return 0;
+}
+
+void *second(void *arg) {
+ assert(tls_var == p_tls_var);
+ *p_tls_var = 1;
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+ pthread_t p;
+ assert(0 == pthread_create(&p, 0, first, 0));
+ assert(0 == pthread_join(p, 0));
+ assert(0 == pthread_create(&p, 0, second, 0));
+ assert(0 == pthread_join(p, 0));
+ return 0;
+}
diff --git a/test/asan/TestCases/Posix/allow_user_segv.cc b/test/asan/TestCases/Posix/allow_user_segv.cc
new file mode 100644
index 000000000000..b6443fab85df
--- /dev/null
+++ b/test/asan/TestCases/Posix/allow_user_segv.cc
@@ -0,0 +1,59 @@
+// Regression test for
+// https://code.google.com/p/address-sanitizer/issues/detail?id=180
+
+// RUN: %clangxx_asan -O0 %s -o %t && ASAN_OPTIONS=allow_user_segv_handler=true not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && ASAN_OPTIONS=allow_user_segv_handler=true not %run %t 2>&1 | FileCheck %s
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+struct sigaction original_sigaction_sigbus;
+struct sigaction original_sigaction_sigsegv;
+
+void User_OnSIGSEGV(int signum, siginfo_t *siginfo, void *context) {
+ fprintf(stderr, "User sigaction called\n");
+ struct sigaction original_sigaction;
+ if (signum == SIGBUS)
+ original_sigaction = original_sigaction_sigbus;
+ else if (signum == SIGSEGV)
+ original_sigaction = original_sigaction_sigsegv;
+ else {
+ printf("Invalid signum");
+ exit(1);
+ }
+ if (original_sigaction.sa_flags | SA_SIGINFO)
+ original_sigaction.sa_sigaction(signum, siginfo, context);
+ else
+ original_sigaction.sa_handler(signum);
+}
+
+int DoSEGV() {
+ volatile int *x = 0;
+ return *x;
+}
+
+int InstallHandler(int signum, struct sigaction *original_sigaction) {
+ struct sigaction user_sigaction;
+ user_sigaction.sa_sigaction = User_OnSIGSEGV;
+ user_sigaction.sa_flags = SA_SIGINFO;
+ if (sigaction(signum, &user_sigaction, original_sigaction)) {
+ perror("sigaction");
+ return 1;
+ }
+ return 0;
+}
+
+int main() {
+ // Let's install handlers for both SIGSEGV and SIGBUS, since pre-Yosemite
+ // 32-bit Darwin triggers SIGBUS instead.
+ if (InstallHandler(SIGSEGV, &original_sigaction_sigsegv)) return 1;
+ if (InstallHandler(SIGBUS, &original_sigaction_sigbus)) return 1;
+ fprintf(stderr, "User sigaction installed\n");
+ return DoSEGV();
+}
+
+// CHECK: User sigaction installed
+// CHECK-NEXT: User sigaction called
+// CHECK-NEXT: ASAN:SIGSEGV
+// CHECK: AddressSanitizer: SEGV on unknown address
diff --git a/test/asan/TestCases/Posix/asan-symbolize-sanity-test.cc b/test/asan/TestCases/Posix/asan-symbolize-sanity-test.cc
new file mode 100644
index 000000000000..6ed02f4d5374
--- /dev/null
+++ b/test/asan/TestCases/Posix/asan-symbolize-sanity-test.cc
@@ -0,0 +1,63 @@
+// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316
+// XFAIL: android
+//
+// Check that asan_symbolize.py script works (for binaries, ASan RTL and
+// shared object files.
+
+// RUN: %clangxx_asan -O0 -DSHARED_LIB %s -fPIC -shared -o %t-so.so
+// RUN: %clangxx_asan -O0 %s -o %t
+// RUN: env ASAN_OPTIONS=symbolize=0 not %run %t 2>&1 | %asan_symbolize | FileCheck %s
+// XFAIL: arm-linux-gnueabi
+// XFAIL: armv7l-unknown-linux-gnueabihf
+
+#if !defined(SHARED_LIB)
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <string>
+
+using std::string;
+
+typedef void (fun_t)(int*, int);
+
+int main(int argc, char *argv[]) {
+ string path = string(argv[0]) + "-so.so";
+ printf("opening %s ... \n", path.c_str());
+ void *lib = dlopen(path.c_str(), RTLD_NOW);
+ if (!lib) {
+ printf("error in dlopen(): %s\n", dlerror());
+ return 1;
+ }
+ fun_t *inc2 = (fun_t*)dlsym(lib, "inc2");
+ if (!inc2) return 1;
+ printf("ok\n");
+ int *array = (int*)malloc(40);
+ inc2(array, 1);
+ inc2(array, -1); // BOOM
+ // CHECK: ERROR: AddressSanitizer: heap-buffer-overflow
+ // CHECK: READ of size 4 at 0x{{.*}}
+ // CHECK: #0 {{.*}} in inc2 {{.*}}asan-symbolize-sanity-test.cc:[[@LINE+21]]
+ // CHECK: #1 {{.*}} in main {{.*}}asan-symbolize-sanity-test.cc:[[@LINE-4]]
+ // CHECK: allocated by thread T{{.*}} here:
+ // CHECK: #{{.*}} in {{(wrap_|__interceptor_)?}}malloc
+ // CHECK: #{{.*}} in main {{.*}}asan-symbolize-sanity-test.cc:[[@LINE-9]]
+ return 0;
+}
+#else // SHARED_LIBS
+#include <stdio.h>
+#include <string.h>
+
+int pad[10];
+int GLOB[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+extern "C"
+void inc(int index) {
+ GLOB[index]++;
+}
+
+extern "C"
+void inc2(int *a, int index) {
+ a[index]++;
+}
+#endif // SHARED_LIBS
diff --git a/test/asan/TestCases/Posix/asprintf.cc b/test/asan/TestCases/Posix/asprintf.cc
new file mode 100644
index 000000000000..6946e5013d2c
--- /dev/null
+++ b/test/asan/TestCases/Posix/asprintf.cc
@@ -0,0 +1,20 @@
+// RUN: %clangxx_asan -O0 %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv) {
+ char *p;
+ int res = asprintf(&p, "%d", argc);
+ fprintf(stderr, "x%d %sx\n", res, p);
+ // CHECK: x1 1x
+ free(p);
+ fprintf(stderr, "DONE\n");
+ // CHECK: DONE
+ return 0;
+}
diff --git a/test/asan/TestCases/Posix/assign_large_valloc_to_global.cc b/test/asan/TestCases/Posix/assign_large_valloc_to_global.cc
new file mode 100644
index 000000000000..ad547ce0ce1b
--- /dev/null
+++ b/test/asan/TestCases/Posix/assign_large_valloc_to_global.cc
@@ -0,0 +1,9 @@
+// Make sure we don't report a leak nor hang.
+// RUN: %clangxx_asan -O3 %s -o %t && %run %t
+#include <stdlib.h>
+#include <unistd.h>
+#if !defined(__APPLE__) && !defined(__FreeBSD__)
+# include <malloc.h>
+#endif // !__APPLE__ && !__FreeBSD__
+int *p = (int*)valloc(1 << 20);
+int main() { }
diff --git a/test/asan/TestCases/Posix/glob.cc b/test/asan/TestCases/Posix/glob.cc
new file mode 100644
index 000000000000..e0eeb33cca24
--- /dev/null
+++ b/test/asan/TestCases/Posix/glob.cc
@@ -0,0 +1,33 @@
+// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316
+// XFAIL: android
+//
+// RUN: %clangxx_asan -O0 %s -o %t && %run %t %p 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && %run %t %p 2>&1 | FileCheck %s
+// XFAIL: arm-linux-gnueabi
+
+#include <assert.h>
+#include <glob.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <string>
+
+
+int main(int argc, char *argv[]) {
+ std::string path = argv[1];
+ std::string pattern = path + "/glob_test_root/*a";
+ printf("pattern: %s\n", pattern.c_str());
+
+ glob_t globbuf;
+ int res = glob(pattern.c_str(), 0, 0, &globbuf);
+
+ printf("%d %s\n", errno, strerror(errno));
+ assert(res == 0);
+ assert(globbuf.gl_pathc == 2);
+ printf("%zu\n", strlen(globbuf.gl_pathv[0]));
+ printf("%zu\n", strlen(globbuf.gl_pathv[1]));
+ globfree(&globbuf);
+ printf("PASS\n");
+ // CHECK: PASS
+ return 0;
+}
diff --git a/test/asan/TestCases/Posix/glob_test_root/aa b/test/asan/TestCases/Posix/glob_test_root/aa
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/asan/TestCases/Posix/glob_test_root/aa
diff --git a/test/asan/TestCases/Posix/glob_test_root/ab b/test/asan/TestCases/Posix/glob_test_root/ab
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/asan/TestCases/Posix/glob_test_root/ab
diff --git a/test/asan/TestCases/Posix/glob_test_root/ba b/test/asan/TestCases/Posix/glob_test_root/ba
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/asan/TestCases/Posix/glob_test_root/ba
diff --git a/test/asan/TestCases/Posix/init-order-dlopen.cc b/test/asan/TestCases/Posix/init-order-dlopen.cc
new file mode 100644
index 000000000000..6f204775eb4e
--- /dev/null
+++ b/test/asan/TestCases/Posix/init-order-dlopen.cc
@@ -0,0 +1,72 @@
+// Regression test for
+// https://code.google.com/p/address-sanitizer/issues/detail?id=178
+
+// Assume we're on Darwin and try to pass -U to the linker. If this flag is
+// unsupported, don't use it.
+// RUN: %clangxx_asan -O0 -DSHARED_LIB %s \
+// RUN: -fPIC -shared -o %t-so.so -Wl,-U,_inc_global || \
+// RUN: %clangxx_asan -O0 -DSHARED_LIB %s \
+// RUN: -fPIC -shared -o %t-so.so
+// If the linker doesn't support --export-dynamic (which is ELF-specific),
+// try to link without that option.
+// FIXME: find a better solution.
+// RUN: %clangxx_asan -O0 %s -pthread -o %t -Wl,--export-dynamic || \
+// RUN: %clangxx_asan -O0 %s -pthread -o %t
+// RUN: ASAN_OPTIONS=strict_init_order=true %run %t 2>&1 | FileCheck %s
+#if !defined(SHARED_LIB)
+#include <dlfcn.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <string>
+
+using std::string;
+
+int foo() {
+ return 42;
+}
+int global = foo();
+
+__attribute__((visibility("default")))
+extern "C"
+void inc_global() {
+ global++;
+}
+
+void *global_poller(void *arg) {
+ while (true) {
+ if (global != 42)
+ break;
+ usleep(100);
+ }
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+ pthread_t p;
+ pthread_create(&p, 0, global_poller, 0);
+ string path = string(argv[0]) + "-so.so";
+ if (0 == dlopen(path.c_str(), RTLD_NOW)) {
+ fprintf(stderr, "dlerror: %s\n", dlerror());
+ return 1;
+ }
+ pthread_join(p, 0);
+ printf("PASSED\n");
+ // CHECK: PASSED
+ return 0;
+}
+#else // SHARED_LIB
+#include <stdio.h>
+#include <unistd.h>
+
+extern "C" void inc_global();
+
+int slow_init() {
+ sleep(1);
+ inc_global();
+ return 42;
+}
+
+int slowly_init_glob = slow_init();
+#endif // SHARED_LIB
diff --git a/test/asan/TestCases/Posix/ioctl.cc b/test/asan/TestCases/Posix/ioctl.cc
new file mode 100644
index 000000000000..78f152fe93fe
--- /dev/null
+++ b/test/asan/TestCases/Posix/ioctl.cc
@@ -0,0 +1,24 @@
+// RUN: %clangxx_asan -O0 -g %s -o %t && ASAN_OPTIONS=handle_ioctl=1 not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 -g %s -o %t && ASAN_OPTIONS=handle_ioctl=1 not %run %t 2>&1 | FileCheck %s
+
+// RUN: %clangxx_asan -O0 -g %s -o %t && %run %t
+// RUN: %clangxx_asan -O3 -g %s -o %t && %run %t
+
+#include <assert.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+int main(int argc, char **argv) {
+ int fd = socket(AF_INET, SOCK_DGRAM, 0);
+
+ int nonblock;
+ int res = ioctl(fd, FIONBIO, &nonblock + 1);
+ // CHECK: AddressSanitizer: stack-buffer-overflow
+ // CHECK: READ of size 4 at
+ // CHECK: {{#.* in main .*ioctl.cc:}}[[@LINE-3]]
+ assert(res == 0);
+ close(fd);
+ return 0;
+}
diff --git a/test/asan/TestCases/Posix/large_allocator_unpoisons_on_free.cc b/test/asan/TestCases/Posix/large_allocator_unpoisons_on_free.cc
new file mode 100644
index 000000000000..0a4998049cb0
--- /dev/null
+++ b/test/asan/TestCases/Posix/large_allocator_unpoisons_on_free.cc
@@ -0,0 +1,39 @@
+// Test that LargeAllocator unpoisons memory before releasing it to the OS.
+// RUN: %clangxx_asan %s -o %t
+// The memory is released only when the deallocated chunk leaves the quarantine,
+// otherwise the mmap(p, ...) call overwrites the malloc header.
+// RUN: ASAN_OPTIONS=quarantine_size=1 %run %t
+
+#include <assert.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifdef __ANDROID__
+#include <malloc.h>
+void *my_memalign(size_t boundary, size_t size) {
+ return memalign(boundary, size);
+}
+#else
+void *my_memalign(size_t boundary, size_t size) {
+ void *p;
+ posix_memalign(&p, boundary, size);
+ return p;
+}
+#endif
+
+int main() {
+ const long kPageSize = sysconf(_SC_PAGESIZE);
+ void *p = my_memalign(kPageSize, 1024 * 1024);
+ free(p);
+
+ char *q = (char *)mmap(p, kPageSize, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0);
+ assert(q == p);
+
+ memset(q, 42, kPageSize);
+
+ munmap(q, kPageSize);
+ return 0;
+}
diff --git a/test/asan/TestCases/Posix/lit.local.cfg b/test/asan/TestCases/Posix/lit.local.cfg
new file mode 100644
index 000000000000..60a9460820a6
--- /dev/null
+++ b/test/asan/TestCases/Posix/lit.local.cfg
@@ -0,0 +1,9 @@
+def getRoot(config):
+ if not config.parent:
+ return config
+ return getRoot(config.parent)
+
+root = getRoot(config)
+
+if root.host_os in ['Windows']:
+ config.unsupported = True
diff --git a/test/asan/TestCases/Posix/new_array_cookie_test.cc b/test/asan/TestCases/Posix/new_array_cookie_test.cc
new file mode 100644
index 000000000000..85d51f361835
--- /dev/null
+++ b/test/asan/TestCases/Posix/new_array_cookie_test.cc
@@ -0,0 +1,24 @@
+// REQUIRES: asan-64-bits
+// RUN: %clangxx_asan -O3 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: ASAN_OPTIONS=poison_array_cookie=1 not %run %t 2>&1 | FileCheck %s
+// RUN: ASAN_OPTIONS=poison_array_cookie=0 not %run %t 2>&1 | FileCheck %s --check-prefix=NO_COOKIE
+#include <stdio.h>
+#include <stdlib.h>
+struct C {
+ int x;
+ ~C() {
+ fprintf(stderr, "ZZZZZZZZ\n");
+ exit(1);
+ }
+};
+
+int main(int argc, char **argv) {
+ C *buffer = new C[argc];
+ buffer[-2].x = 10;
+// CHECK: AddressSanitizer: heap-buffer-overflow
+// CHECK: in main {{.*}}new_array_cookie_test.cc:[[@LINE-2]]
+// CHECK: is located 0 bytes inside of 12-byte region
+// NO_COOKIE: ZZZZZZZZ
+ delete [] buffer;
+}
diff --git a/test/asan/TestCases/Posix/new_array_cookie_uaf_test.cc b/test/asan/TestCases/Posix/new_array_cookie_uaf_test.cc
new file mode 100644
index 000000000000..c35ccebb8c79
--- /dev/null
+++ b/test/asan/TestCases/Posix/new_array_cookie_uaf_test.cc
@@ -0,0 +1,38 @@
+// REQUIRES: asan-64-bits
+// RUN: %clangxx_asan -O3 %s -o %t
+// RUN: ASAN_OPTIONS=poison_array_cookie=1 not %run %t 2>&1 | FileCheck %s --check-prefix=COOKIE
+// RUN: ASAN_OPTIONS=poison_array_cookie=0 not %run %t 2>&1 | FileCheck %s --check-prefix=NO_COOKIE
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+int dtor_counter;
+struct C {
+ int x;
+ ~C() {
+ dtor_counter++;
+ fprintf(stderr, "DTOR %d\n", dtor_counter);
+ }
+};
+
+__attribute__((noinline)) void Delete(C *c) { delete[] c; }
+__attribute__((no_sanitize_address)) void Write42ToCookie(C *c) {
+ long *p = reinterpret_cast<long*>(c);
+ p[-1] = 42;
+}
+
+int main(int argc, char **argv) {
+ C *buffer = new C[argc];
+ delete [] buffer;
+ Write42ToCookie(buffer);
+ delete [] buffer;
+// COOKIE: DTOR 1
+// COOKIE-NOT: DTOR 2
+// COOKIE: AddressSanitizer: loaded array cookie from free-d memory
+// COOKIE: AddressSanitizer: attempting double-free
+// NO_COOKIE: DTOR 1
+// NO_COOKIE: DTOR 43
+// NO_COOKIE-NOT: DTOR 44
+// NO_COOKIE-NOT: AddressSanitizer: loaded array cookie from free-d memory
+// NO_COOKIE: AddressSanitizer: attempting double-free
+
+}
diff --git a/test/asan/TestCases/Posix/new_array_cookie_with_new_from_class.cc b/test/asan/TestCases/Posix/new_array_cookie_with_new_from_class.cc
new file mode 100644
index 000000000000..1cea6f68adb2
--- /dev/null
+++ b/test/asan/TestCases/Posix/new_array_cookie_with_new_from_class.cc
@@ -0,0 +1,38 @@
+// Test that we do not poison the array cookie if the operator new is defined
+// inside the class.
+// RUN: %clangxx_asan %s -o %t && %run %t
+//
+// XFAIL: android
+// XFAIL: armv7l-unknown-linux-gnueabihf
+#include <new>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <assert.h>
+struct Foo {
+ void *operator new(size_t s) { return Allocate(s); }
+ void *operator new[] (size_t s) { return Allocate(s); }
+ ~Foo();
+ static void *allocated;
+ static void *Allocate(size_t s) {
+ assert(!allocated);
+ return allocated = ::new char[s];
+ }
+};
+
+Foo::~Foo() {}
+void *Foo::allocated;
+
+Foo *getFoo(size_t n) {
+ return new Foo[n];
+}
+
+int main() {
+ Foo *foo = getFoo(10);
+ fprintf(stderr, "foo : %p\n", foo);
+ fprintf(stderr, "alloc: %p\n", Foo::allocated);
+ assert(reinterpret_cast<uintptr_t>(foo) ==
+ reinterpret_cast<uintptr_t>(Foo::allocated) + sizeof(void*));
+ *reinterpret_cast<uintptr_t*>(Foo::allocated) = 42;
+ return 0;
+}
diff --git a/test/asan/TestCases/Posix/readv.cc b/test/asan/TestCases/Posix/readv.cc
new file mode 100644
index 000000000000..27436a1ad3d9
--- /dev/null
+++ b/test/asan/TestCases/Posix/readv.cc
@@ -0,0 +1,32 @@
+// RUN: %clangxx_asan -O0 %s -o %t && %run %t
+// RUN: %clangxx_asan -O0 %s -DPOSITIVE -o %t && not %run %t 2>&1 | FileCheck %s
+
+// Test the readv() interceptor.
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/uio.h>
+#include <time.h>
+
+int main() {
+ char buf[2011];
+ struct iovec iov[2];
+#ifdef POSITIVE
+ char * volatile buf_ = buf;
+ iov[0].iov_base = buf_ - 1;
+#else
+ iov[0].iov_base = buf + 1;
+#endif
+ iov[0].iov_len = 5;
+ iov[1].iov_base = buf + 10;
+ iov[1].iov_len = 2000;
+ int fd = open("/etc/hosts", O_RDONLY);
+ assert(fd > 0);
+ readv(fd, iov, 2);
+ // CHECK: WRITE of size 5 at
+ close(fd);
+ return 0;
+}
diff --git a/test/asan/TestCases/Posix/shared-lib-test.cc b/test/asan/TestCases/Posix/shared-lib-test.cc
new file mode 100644
index 000000000000..a0827b5fefbf
--- /dev/null
+++ b/test/asan/TestCases/Posix/shared-lib-test.cc
@@ -0,0 +1,57 @@
+// RUN: %clangxx_asan -O0 -DSHARED_LIB %s -fPIC -shared -o %t-so.so
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 -DSHARED_LIB %s -fPIC -shared -o %t-so.so
+// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 -DSHARED_LIB %s -fPIC -shared -o %t-so.so
+// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 -DSHARED_LIB %s -fPIC -shared -o %t-so.so
+// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// XFAIL: arm-linux-gnueabi
+
+#if !defined(SHARED_LIB)
+#include <dlfcn.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <string>
+
+using std::string;
+
+typedef void (fun_t)(int x);
+
+int main(int argc, char *argv[]) {
+ string path = string(argv[0]) + "-so.so";
+ printf("opening %s ... \n", path.c_str());
+ void *lib = dlopen(path.c_str(), RTLD_NOW);
+ if (!lib) {
+ printf("error in dlopen(): %s\n", dlerror());
+ return 1;
+ }
+ fun_t *inc = (fun_t*)dlsym(lib, "inc");
+ if (!inc) return 1;
+ printf("ok\n");
+ inc(1);
+ inc(-1); // BOOM
+ // CHECK: {{.*ERROR: AddressSanitizer: global-buffer-overflow}}
+ // CHECK: {{READ of size 4 at 0x.* thread T0}}
+ // CHECK: {{ #0 0x.*}}
+ // CHECK: {{ #1 0x.* in main .*shared-lib-test.cc:}}[[@LINE-4]]
+ return 0;
+}
+#else // SHARED_LIB
+#include <stdio.h>
+#include <string.h>
+
+int pad[10];
+int GLOB[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+extern "C"
+void inc(int index) {
+ GLOB[index]++;
+}
+
+extern "C"
+void inc2(int *a, int index) {
+ a[index]++;
+}
+#endif // SHARED_LIB
diff --git a/test/asan/TestCases/Posix/start-deactivated.cc b/test/asan/TestCases/Posix/start-deactivated.cc
new file mode 100644
index 000000000000..d60677a8a5bb
--- /dev/null
+++ b/test/asan/TestCases/Posix/start-deactivated.cc
@@ -0,0 +1,69 @@
+// Test for ASAN_OPTIONS=start_deactivated=1 mode.
+// Main executable is uninstrumented, but linked to ASan runtime. The shared
+// library is instrumented. Memory errors before dlopen are not detected.
+
+// RUN: %clangxx_asan -O0 -DSHARED_LIB %s -fPIC -shared -o %t-so.so
+// RUN: %clangxx -O0 %s -c -o %t.o
+// RUN: %clangxx_asan -O0 %t.o -o %t
+// RUN: ASAN_OPTIONS=start_deactivated=1 not %run %t 2>&1 | FileCheck %s
+// XFAIL: arm-linux-gnueabi
+// XFAIL: armv7l-unknown-linux-gnueabihf
+
+#if !defined(SHARED_LIB)
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "sanitizer/asan_interface.h"
+
+void test_malloc_shadow() {
+ char *p = (char *)malloc(100);
+ char *q = (char *)__asan_region_is_poisoned(p + 95, 8);
+ fprintf(stderr, "=%zd=\n", q ? q - (p + 95) : -1);
+ free(p);
+}
+
+typedef void (*Fn)();
+
+int main(int argc, char *argv[]) {
+ test_malloc_shadow();
+ // CHECK: =-1=
+
+ std::string path = std::string(argv[0]) + "-so.so";
+ void *dso = dlopen(path.c_str(), RTLD_NOW);
+ if (!dso) {
+ fprintf(stderr, "dlopen failed: %s\n", dlerror());
+ return 1;
+ }
+
+ test_malloc_shadow();
+ // CHECK: =5=
+
+ void *fn = dlsym(dso, "do_another_bad_thing");
+ if (!fn) {
+ fprintf(stderr, "dlsym failed: %s\n", dlerror());
+ return 1;
+ }
+
+ ((Fn)fn)();
+ // CHECK: AddressSanitizer: heap-buffer-overflow
+ // CHECK: READ of size 1
+ // CHECK: {{#0 .* in do_another_bad_thing}}
+ // CHECK: is located 5 bytes to the right of 100-byte region
+ // CHECK: in do_another_bad_thing
+
+ return 0;
+}
+#else // SHARED_LIB
+#include <stdio.h>
+#include <stdlib.h>
+
+extern "C" void do_another_bad_thing() {
+ char *volatile p = (char *)malloc(100);
+ printf("%hhx\n", p[105]);
+}
+#endif // SHARED_LIB
diff --git a/test/asan/TestCases/Posix/strerror_r_test.cc b/test/asan/TestCases/Posix/strerror_r_test.cc
new file mode 100644
index 000000000000..e6df441770df
--- /dev/null
+++ b/test/asan/TestCases/Posix/strerror_r_test.cc
@@ -0,0 +1,14 @@
+// RUN: %clangxx_asan -O0 %s -o %t && %run %t
+
+// Regression test for PR17138.
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+
+int main() {
+ char buf[1024];
+ char *res = (char *)strerror_r(300, buf, sizeof(buf));
+ printf("%p\n", res);
+ return 0;
+}
diff --git a/test/asan/TestCases/Posix/tsd_dtor_leak.cc b/test/asan/TestCases/Posix/tsd_dtor_leak.cc
new file mode 100644
index 000000000000..32253afc8b25
--- /dev/null
+++ b/test/asan/TestCases/Posix/tsd_dtor_leak.cc
@@ -0,0 +1,39 @@
+// Regression test for a leak in tsd:
+// https://code.google.com/p/address-sanitizer/issues/detail?id=233
+// RUN: %clangxx_asan -O1 %s -pthread -o %t
+// RUN: ASAN_OPTIONS=quarantine_size=1 %run %t
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <sanitizer/allocator_interface.h>
+
+static pthread_key_t tsd_key;
+
+void *Thread(void *) {
+ pthread_setspecific(tsd_key, malloc(10));
+ return 0;
+}
+
+static volatile void *v;
+
+void Dtor(void *tsd) {
+ v = malloc(10000);
+ free(tsd);
+ free((void*)v); // The bug was that this was leaking.
+}
+
+int main() {
+ assert(0 == pthread_key_create(&tsd_key, Dtor));
+ size_t old_heap_size = 0;
+ for (int i = 0; i < 10; i++) {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ pthread_join(t, 0);
+ size_t new_heap_size = __sanitizer_get_heap_size();
+ fprintf(stderr, "heap size: new: %zd old: %zd\n", new_heap_size, old_heap_size);
+ if (old_heap_size)
+ assert(old_heap_size == new_heap_size);
+ old_heap_size = new_heap_size;
+ }
+}
diff --git a/test/asan/TestCases/Posix/wait.cc b/test/asan/TestCases/Posix/wait.cc
new file mode 100644
index 000000000000..99d0212acfab
--- /dev/null
+++ b/test/asan/TestCases/Posix/wait.cc
@@ -0,0 +1,45 @@
+// RUN: %clangxx_asan -DWAIT -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -DWAIT -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+// RUN: %clangxx_asan -DWAITPID -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -DWAITPID -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+// RUN: %clangxx_asan -DWAIT3 -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -DWAIT3 -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+// RUN: %clangxx_asan -DWAIT3_RUSAGE -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -DWAIT3_RUSAGE -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+
+#include <assert.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+int main(int argc, char **argv) {
+ pid_t pid = fork();
+ if (pid) { // parent
+ int x[3];
+ int *status = x + argc * 3;
+ int res;
+#if defined(WAIT)
+ res = wait(status);
+#elif defined(WAITPID)
+ res = waitpid(pid, status, WNOHANG);
+#elif defined(WAIT3)
+ res = wait3(status, WNOHANG, NULL);
+#elif defined(WAIT3_RUSAGE)
+ struct rusage *ru = (struct rusage*)(x + argc * 3);
+ int good_status;
+ res = wait3(&good_status, WNOHANG, ru);
+#endif
+ // CHECK: stack-buffer-overflow
+ // CHECK: {{WRITE of size .* at 0x.* thread T0}}
+ // CHECK: {{in .*wait}}
+ // CHECK: {{in main .*wait.cc:}}
+ // CHECK: is located in stack of thread T0 at offset
+ // CHECK: {{in main}}
+ return res == -1 ? 1 : 0;
+ }
+ // child
+ return 0;
+}
diff --git a/test/asan/TestCases/Posix/wait4.cc b/test/asan/TestCases/Posix/wait4.cc
new file mode 100644
index 000000000000..b95246efa0e4
--- /dev/null
+++ b/test/asan/TestCases/Posix/wait4.cc
@@ -0,0 +1,43 @@
+// RUN: %clangxx_asan -DWAIT4 -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -DWAIT4 -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+// RUN: %clangxx_asan -DWAIT4_RUSAGE -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -DWAIT4_RUSAGE -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+// XFAIL: android
+
+#include <assert.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+int main(int argc, char **argv) {
+ // This test passes on some versions of Android NDK and fails on other.
+ // https://code.google.com/p/memory-sanitizer/issues/detail?id=64
+ // Make it fail unconditionally on Android.
+#ifdef __ANDROID__
+ return 0;
+#endif
+
+ pid_t pid = fork();
+ if (pid) { // parent
+ int x[3];
+ int *status = x + argc * 3;
+ int res;
+#if defined(WAIT4)
+ res = wait4(pid, status, WNOHANG, NULL);
+#elif defined(WAIT4_RUSAGE)
+ struct rusage *ru = (struct rusage*)(x + argc * 3);
+ int good_status;
+ res = wait4(pid, &good_status, WNOHANG, ru);
+#endif
+ // CHECK: stack-buffer-overflow
+ // CHECK: {{WRITE of size .* at 0x.* thread T0}}
+ // CHECK: {{in .*wait}}
+ // CHECK: {{in main .*wait4.cc:}}
+ // CHECK: is located in stack of thread T0 at offset
+ // CHECK: {{in main}}
+ return res == -1 ? 1 : 0;
+ }
+ // child
+ return 0;
+}
diff --git a/test/asan/TestCases/Posix/waitid.cc b/test/asan/TestCases/Posix/waitid.cc
new file mode 100644
index 000000000000..8b516dca9086
--- /dev/null
+++ b/test/asan/TestCases/Posix/waitid.cc
@@ -0,0 +1,28 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <signal.h>
+
+int main(int argc, char **argv) {
+ pid_t pid = fork();
+ if (pid) { // parent
+ int x[3];
+ int *status = x + argc * 3;
+ int res;
+
+ siginfo_t *si = (siginfo_t*)(x + argc * 3);
+ res = waitid(P_ALL, 0, si, WEXITED | WNOHANG);
+ // CHECK: stack-buffer-overflow
+ // CHECK: {{WRITE of size .* at 0x.* thread T0}}
+ // CHECK: {{in .*waitid}}
+ // CHECK: {{in main .*waitid.cc:}}
+ // CHECK: is located in stack of thread T0 at offset
+ // CHECK: {{in main}}
+ return res != -1;
+ }
+ // child
+ return 0;
+}
diff --git a/test/asan/TestCases/Windows/aligned_mallocs.cc b/test/asan/TestCases/Windows/aligned_mallocs.cc
new file mode 100644
index 000000000000..df740b64e51c
--- /dev/null
+++ b/test/asan/TestCases/Windows/aligned_mallocs.cc
@@ -0,0 +1,29 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: %run %t
+
+#include <windows.h>
+
+#define CHECK_ALIGNED(ptr,alignment) \
+ do { \
+ if (((uintptr_t)(ptr) % (alignment)) != 0) \
+ return __LINE__; \
+ } \
+ while(0)
+
+int main(void) {
+ int *p = (int*)_aligned_malloc(1024 * sizeof(int), 32);
+ CHECK_ALIGNED(p, 32);
+ p[512] = 0;
+ _aligned_free(p);
+
+ p = (int*)_aligned_malloc(128, 128);
+ CHECK_ALIGNED(p, 128);
+ p = (int*)_aligned_realloc(p, 2048 * sizeof(int), 128);
+ CHECK_ALIGNED(p, 128);
+ p[1024] = 0;
+ if (_aligned_msize(p, 128, 0) != 2048 * sizeof(int))
+ return __LINE__;
+ _aligned_free(p);
+
+ return 0;
+}
diff --git a/test/asan/TestCases/Windows/allocators_sanity.cc b/test/asan/TestCases/Windows/allocators_sanity.cc
new file mode 100644
index 000000000000..66a862d7aca5
--- /dev/null
+++ b/test/asan/TestCases/Windows/allocators_sanity.cc
@@ -0,0 +1,37 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: %run %t | FileCheck %s
+
+#include <malloc.h>
+#include <stdio.h>
+
+int main() {
+ int *p = (int*)malloc(1024 * sizeof(int));
+ p[512] = 0;
+ free(p);
+
+ p = (int*)malloc(128);
+ p = (int*)realloc(p, 2048 * sizeof(int));
+ p[1024] = 0;
+ free(p);
+
+ p = (int*)calloc(16, sizeof(int));
+ if (p[8] != 0)
+ return 1;
+ p[15]++;
+ if (16 * sizeof(int) != _msize(p))
+ return 2;
+ free(p);
+
+ p = new int;
+ *p = 42;
+ delete p;
+
+ p = new int[42];
+ p[15]++;
+ delete [] p;
+
+ printf("All ok\n");
+// CHECK: All ok
+
+ return 0;
+}
diff --git a/test/asan/TestCases/Windows/beginthreadex.cc b/test/asan/TestCases/Windows/beginthreadex.cc
new file mode 100644
index 000000000000..f2b2b4511ad8
--- /dev/null
+++ b/test/asan/TestCases/Windows/beginthreadex.cc
@@ -0,0 +1,21 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: %run %t
+
+#include <windows.h>
+#include <process.h>
+
+unsigned WINAPI thread_proc(void *) {
+ volatile char stack_buffer[42];
+ for (int i = 0; i < sizeof(stack_buffer); ++i)
+ stack_buffer[i] = 42;
+ return 0;
+}
+
+int main() {
+ HANDLE thr = (HANDLE)_beginthreadex(NULL, 0, thread_proc, NULL, 0, NULL);
+ if (thr == 0)
+ return 1;
+ if (WAIT_OBJECT_0 != WaitForSingleObject(thr, INFINITE))
+ return 2;
+ CloseHandle(thr);
+}
diff --git a/test/asan/TestCases/Windows/bitfield.cc b/test/asan/TestCases/Windows/bitfield.cc
new file mode 100644
index 000000000000..253a759b98df
--- /dev/null
+++ b/test/asan/TestCases/Windows/bitfield.cc
@@ -0,0 +1,21 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: %run %t
+
+#include <windows.h>
+
+typedef struct _S {
+ unsigned int bf1:1;
+ unsigned int bf2:2;
+ unsigned int bf3:3;
+ unsigned int bf4:4;
+} S;
+
+int main(void) {
+ S *s = (S*)malloc(sizeof(S));
+ s->bf1 = 1;
+ s->bf2 = 2;
+ s->bf3 = 3;
+ s->bf4 = 4;
+ free(s);
+ return 0;
+}
diff --git a/test/asan/TestCases/Windows/bitfield_uaf.cc b/test/asan/TestCases/Windows/bitfield_uaf.cc
new file mode 100644
index 000000000000..f49d671e3eb3
--- /dev/null
+++ b/test/asan/TestCases/Windows/bitfield_uaf.cc
@@ -0,0 +1,34 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <windows.h>
+
+typedef struct _S {
+ unsigned int bf1:1;
+ unsigned int bf2:2;
+ unsigned int bf3:3;
+ unsigned int bf4:4;
+} S;
+
+void make_access(S *s) {
+ s->bf2 = 2;
+// CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: READ of size {{[124]}} at [[ADDR]]
+// CHECK: {{#0 .* make_access .*bitfield_uaf.cc}}:[[@LINE-3]]
+// CHECK: {{#1 .* main}}
+}
+
+int main(void) {
+ S *s = (S*)malloc(sizeof(S));
+ free(s);
+// CHECK: [[ADDR]] is located 0 bytes inside of 4-byte region
+// CHECK-LABEL: freed by thread T0 here:
+// CHECK: {{#0 .* free }}
+// CHECK: {{#1 .* main .*bitfield_uaf.cc}}:[[@LINE-4]]
+// CHECK-LABEL: previously allocated by thread T0 here:
+// CHECK: {{#0 .* malloc }}
+// CHECK: {{#1 .* main .*bitfield_uaf.cc}}:[[@LINE-8]]
+ make_access(s);
+ return 0;
+}
+
diff --git a/test/asan/TestCases/Windows/calloc_left_oob.cc b/test/asan/TestCases/Windows/calloc_left_oob.cc
new file mode 100644
index 000000000000..459025bde92c
--- /dev/null
+++ b/test/asan/TestCases/Windows/calloc_left_oob.cc
@@ -0,0 +1,17 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <malloc.h>
+
+int main() {
+ int *buffer = (int*)calloc(42, sizeof(int));
+ buffer[-1] = 42;
+// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 4 at [[ADDR]] thread T0
+// CHECK-NEXT: {{#0 .* main .*calloc_left_oob.cc}}:[[@LINE-3]]
+// CHECK: [[ADDR]] is located 4 bytes to the left of 168-byte region
+// CHECK: allocated by thread T0 here:
+// CHECK-NEXT: {{#0 .* calloc }}
+// CHECK-NEXT: {{#1 .* main .*calloc_left_oob.cc}}:[[@LINE-8]]
+ free(buffer);
+}
diff --git a/test/asan/TestCases/Windows/calloc_right_oob.cc b/test/asan/TestCases/Windows/calloc_right_oob.cc
new file mode 100644
index 000000000000..c976b87d9707
--- /dev/null
+++ b/test/asan/TestCases/Windows/calloc_right_oob.cc
@@ -0,0 +1,17 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <malloc.h>
+
+int main() {
+ int *buffer = (int*)calloc(42, sizeof(int));
+ buffer[42] = 42;
+// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 4 at [[ADDR]] thread T0
+// CHECK-NEXT: {{#0 .* main .*calloc_right_oob.cc}}:[[@LINE-3]]
+// CHECK: [[ADDR]] is located 0 bytes to the right of 168-byte region
+// CHECK: allocated by thread T0 here:
+// CHECK-NEXT: {{#0 .* calloc }}
+// CHECK-NEXT: {{#1 .* main .*calloc_right_oob.cc}}:[[@LINE-8]]
+ free(buffer);
+}
diff --git a/test/asan/TestCases/Windows/calloc_uaf.cc b/test/asan/TestCases/Windows/calloc_uaf.cc
new file mode 100644
index 000000000000..db5e70741b72
--- /dev/null
+++ b/test/asan/TestCases/Windows/calloc_uaf.cc
@@ -0,0 +1,20 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <malloc.h>
+
+int main() {
+ int *buffer = (int*)calloc(42, sizeof(int));
+ free(buffer);
+ buffer[0] = 42;
+// CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 4 at [[ADDR]] thread T0
+// CHECK-NEXT: {{#0 .* main .*calloc_uaf.cc}}:[[@LINE-3]]
+// CHECK: [[ADDR]] is located 0 bytes inside of 168-byte region
+// CHECK: freed by thread T0 here:
+// CHECK-NEXT: {{#0 .* free }}
+// CHECK-NEXT: {{#1 .* main .*calloc_uaf.cc}}:[[@LINE-8]]
+// CHECK: previously allocated by thread T0 here:
+// CHECK-NEXT: {{#0 .* calloc }}
+// CHECK-NEXT: {{#1 .* main .*calloc_uaf.cc}}:[[@LINE-12]]
+}
diff --git a/test/asan/TestCases/Windows/crt_initializers.cc b/test/asan/TestCases/Windows/crt_initializers.cc
new file mode 100644
index 000000000000..084f8a45e18a
--- /dev/null
+++ b/test/asan/TestCases/Windows/crt_initializers.cc
@@ -0,0 +1,31 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: %run %t | FileCheck %s
+
+// This is a test for http://code.google.com/p/address-sanitizer/issues/detail?id=305
+
+#include <stdio.h>
+
+typedef void (*FPTR)();
+
+// __xi_a and __xi_z are defined in VC/crt/src/crt0dat.c
+// and are located in .CRT$XIA and .CRT$XIZ respectively.
+extern "C" FPTR __xi_a, __xi_z;
+
+int main() {
+ unsigned count = 0;
+
+ // Iterate through CRT initializers.
+ for (FPTR* it = &__xi_a; it < &__xi_z; ++it) {
+ if (*it)
+ count++;
+ }
+
+ printf("Number of nonzero CRT initializers: %u\n", count);
+// CHECK: Number of nonzero CRT initializers
+}
+
+void call_me_maybe() {}
+
+#pragma data_seg(".CRT$XIB")
+// Add an initializer that shouldn't get its own redzone.
+FPTR run_on_startup = call_me_maybe;
diff --git a/test/asan/TestCases/Windows/demangled_names.cc b/test/asan/TestCases/Windows/demangled_names.cc
new file mode 100644
index 000000000000..a528555b1e16
--- /dev/null
+++ b/test/asan/TestCases/Windows/demangled_names.cc
@@ -0,0 +1,50 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+//
+// This test makes sure ASan symbolizes stack traces the way they are typically
+// symbolized on Windows.
+#include <malloc.h>
+
+namespace foo {
+// A template function in a namespace.
+template<int x>
+void bar(char *p) {
+ *p = x;
+}
+
+// A regular function in a namespace.
+void spam(char *p) {
+ bar<42>(p);
+}
+}
+
+// A multi-argument template with a bool template parameter.
+template<typename T, bool U>
+void baz(T t) {
+ if (U)
+ foo::spam(t);
+}
+
+template<typename T>
+struct A {
+ A(T v) { v_ = v; }
+ ~A();
+ char *v_;
+};
+
+// A destructor of a template class.
+template<>
+A<char*>::~A() {
+ baz<char*, true>(v_);
+}
+
+int main() {
+ char *buffer = (char*)malloc(42);
+ free(buffer);
+ A<char*> a(buffer);
+// CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: foo::bar<42> {{.*}}demangled_names.cc
+// CHECK: foo::spam {{.*}}demangled_names.cc
+// CHECK: baz<char *,1> {{.*}}demangled_names.cc
+// CHECK: A<char *>::~A<char *> {{.*}}demangled_names.cc
+}
diff --git a/test/asan/TestCases/Windows/dll_aligned_mallocs.cc b/test/asan/TestCases/Windows/dll_aligned_mallocs.cc
new file mode 100644
index 000000000000..8b2c4d6dd957
--- /dev/null
+++ b/test/asan/TestCases/Windows/dll_aligned_mallocs.cc
@@ -0,0 +1,34 @@
+// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t
+// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll
+// RUN: %run %t %t.dll | FileCheck %s
+
+#include <malloc.h>
+#include <stdio.h>
+
+#define CHECK_ALIGNED(ptr,alignment) \
+ do { \
+ if (((uintptr_t)(ptr) % (alignment)) != 0) \
+ return __LINE__; \
+ } \
+ while(0)
+
+extern "C" __declspec(dllexport)
+int test_function() {
+ int *p = (int*)_aligned_malloc(1024 * sizeof(int), 32);
+ CHECK_ALIGNED(p, 32);
+ p[512] = 0;
+ _aligned_free(p);
+
+ p = (int*)_aligned_malloc(128, 128);
+ CHECK_ALIGNED(p, 128);
+ p = (int*)_aligned_realloc(p, 2048 * sizeof(int), 128);
+ CHECK_ALIGNED(p, 128);
+ p[1024] = 0;
+ if (_aligned_msize(p, 128, 0) != 2048 * sizeof(int))
+ return __LINE__;
+ _aligned_free(p);
+
+ printf("All ok\n");
+// CHECK: All ok
+ return 0;
+}
diff --git a/test/asan/TestCases/Windows/dll_allocators_sanity.cc b/test/asan/TestCases/Windows/dll_allocators_sanity.cc
new file mode 100644
index 000000000000..1d31f37ca904
--- /dev/null
+++ b/test/asan/TestCases/Windows/dll_allocators_sanity.cc
@@ -0,0 +1,39 @@
+// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t
+// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll
+// RUN: %run %t %t.dll | FileCheck %s
+
+#include <malloc.h>
+#include <stdio.h>
+
+extern "C" __declspec(dllexport)
+int test_function() {
+ int *p = (int*)malloc(1024 * sizeof(int));
+ p[512] = 0;
+ free(p);
+
+ p = (int*)malloc(128);
+ p = (int*)realloc(p, 2048 * sizeof(int));
+ p[1024] = 0;
+ free(p);
+
+ p = (int*)calloc(16, sizeof(int));
+ if (p[8] != 0)
+ return 1;
+ p[15]++;
+ if (16 * sizeof(int) != _msize(p))
+ return 2;
+ free(p);
+
+ p = new int;
+ *p = 42;
+ delete p;
+
+ p = new int[42];
+ p[15]++;
+ delete [] p;
+
+ printf("All ok\n");
+// CHECK: All ok
+
+ return 0;
+}
diff --git a/test/asan/TestCases/Windows/dll_and_lib.cc b/test/asan/TestCases/Windows/dll_and_lib.cc
new file mode 100644
index 000000000000..bddaa32df73b
--- /dev/null
+++ b/test/asan/TestCases/Windows/dll_and_lib.cc
@@ -0,0 +1,19 @@
+// Just make sure we can link an implib into another DLL
+// This used to fail between r212699 and r212814.
+// RUN: %clang_cl_asan -DCONFIG=1 %s -c -Fo%t.1.obj
+// RUN: link /nologo /DLL /OUT:%t.1.dll %t.1.obj %asan_dll_thunk
+// RUN: %clang_cl_asan -DCONFIG=2 %s -c -Fo%t.2.obj
+// RUN: link /nologo /DLL /OUT:%t.2.dll %t.2.obj %t.1.lib %asan_dll_thunk
+// REQUIRES: asan-static-runtime
+
+#if CONFIG==1
+extern "C" __declspec(dllexport) int f1() {
+ int x = 0;
+ return 1;
+}
+#else
+extern "C" __declspec(dllexport) int f2() {
+ int x = 0;
+ return 2;
+}
+#endif
diff --git a/test/asan/TestCases/Windows/dll_cerr.cc b/test/asan/TestCases/Windows/dll_cerr.cc
new file mode 100644
index 000000000000..8f1a699ba801
--- /dev/null
+++ b/test/asan/TestCases/Windows/dll_cerr.cc
@@ -0,0 +1,23 @@
+// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t
+// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll
+// RUN: %run %t %t.dll 2>&1 | FileCheck %s
+
+// Test that it works correctly even with ICF enabled.
+// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll -link /OPT:REF /OPT:ICF
+// RUN: %run %t %t.dll 2>&1 | FileCheck %s
+
+#include <iostream>
+
+extern "C" __declspec(dllexport)
+int test_function() {
+ // Just make sure we can use cout.
+ std::cout << "All ok\n";
+// CHECK: All ok
+
+ // This line forces a declaration of some global basic_ostream internal object that
+ // calls memcpy() in its constructor. This doesn't work if __asan_init is not
+ // called early enough.
+ std::cout << 42;
+// CHECK: 42
+ return 0;
+}
diff --git a/test/asan/TestCases/Windows/dll_host.cc b/test/asan/TestCases/Windows/dll_host.cc
new file mode 100644
index 000000000000..d3b4c149d009
--- /dev/null
+++ b/test/asan/TestCases/Windows/dll_host.cc
@@ -0,0 +1,49 @@
+// This is a host program for DLL tests.
+//
+// Just make sure we can compile this.
+// The actual compile&run sequence is to be done by the DLL tests.
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+//
+// Get the list of ASan wrappers exported by the main module RTL:
+// RUN: dumpbin /EXPORTS %t | grep -o "__asan_wrap[^ ]*" | grep -v @ | sort | uniq > %t.exported_wrappers
+//
+// Get the list of ASan wrappers imported by the DLL RTL:
+// RUN: grep INTERCEPT_LIBRARY_FUNCTION %p/../../../../lib/asan/asan_win_dll_thunk.cc | grep -v define | sed "s/.*(\(.*\)).*/__asan_wrap_\1/" | sort | uniq > %t.dll_imports
+//
+// Now make sure the DLL thunk imports everything:
+// RUN: echo
+// RUN: echo "=== NOTE === If you see a mismatch below, please update asan_win_dll_thunk.cc"
+// RUN: diff %t.dll_imports %t.exported_wrappers
+// REQUIRES: asan-static-runtime
+
+#include <stdio.h>
+#include <windows.h>
+
+int main(int argc, char **argv) {
+ if (argc != 2) {
+ printf("Usage: %s [client].dll\n", argv[0]);
+ return 101;
+ }
+
+ const char *dll_name = argv[1];
+
+ HMODULE h = LoadLibrary(dll_name);
+ if (!h) {
+ printf("Could not load DLL: %s (code: %lu)!\n",
+ dll_name, GetLastError());
+ return 102;
+ }
+
+ typedef int (*test_function)();
+ test_function gf = (test_function)GetProcAddress(h, "test_function");
+ if (!gf) {
+ printf("Could not locate test_function in the DLL!\n");
+ FreeLibrary(h);
+ return 103;
+ }
+
+ int ret = gf();
+
+ FreeLibrary(h);
+ return ret;
+}
diff --git a/test/asan/TestCases/Windows/dll_intercept_memchr.cc b/test/asan/TestCases/Windows/dll_intercept_memchr.cc
new file mode 100644
index 000000000000..1435bdc50127
--- /dev/null
+++ b/test/asan/TestCases/Windows/dll_intercept_memchr.cc
@@ -0,0 +1,21 @@
+// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t
+// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll
+// RUN: not %run %t %t.dll 2>&1 | FileCheck %s
+
+#include <string.h>
+
+extern "C" __declspec(dllexport)
+int test_function() {
+ char buff[6] = "Hello";
+
+ memchr(buff, 'z', 7);
+// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: READ of size 7 at [[ADDR]] thread T0
+// CHECK-NEXT: __asan_wrap_memchr
+// CHECK-NEXT: memchr
+// CHECK-NEXT: test_function {{.*}}dll_intercept_memchr.cc:[[@LINE-5]]
+// CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} in frame
+// CHECK-NEXT: test_function {{.*}}dll_intercept_memchr.cc
+// CHECK: 'buff' <== Memory access at offset {{.*}} overflows this variable
+ return 0;
+}
diff --git a/test/asan/TestCases/Windows/dll_intercept_memcpy.cc b/test/asan/TestCases/Windows/dll_intercept_memcpy.cc
new file mode 100644
index 000000000000..736e6969d521
--- /dev/null
+++ b/test/asan/TestCases/Windows/dll_intercept_memcpy.cc
@@ -0,0 +1,32 @@
+// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t
+// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll
+// RUN: not %run %t %t.dll 2>&1 | FileCheck %s
+
+// Test that it works correctly even with ICF enabled.
+// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll -link /OPT:REF /OPT:ICF
+// RUN: not %run %t %t.dll 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <string.h>
+
+extern "C" __declspec(dllexport)
+int test_function() {
+ char buff1[6] = "Hello", buff2[5];
+
+ memcpy(buff2, buff1, 5);
+ if (buff1[2] != buff2[2])
+ return 2;
+ printf("Initial test OK\n");
+ fflush(0);
+// CHECK: Initial test OK
+
+ memcpy(buff2, buff1, 6);
+// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 6 at [[ADDR]] thread T0
+// CHECK-NEXT: __asan_{{.*}}memcpy
+// CHECK-NEXT: test_function {{.*}}dll_intercept_memcpy.cc:[[@LINE-4]]
+// CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} in frame
+// CHECK-NEXT: test_function {{.*}}dll_intercept_memcpy.cc
+// CHECK: 'buff2' <== Memory access at offset {{.*}} overflows this variable
+ return 0;
+}
diff --git a/test/asan/TestCases/Windows/dll_intercept_memcpy_indirect.cc b/test/asan/TestCases/Windows/dll_intercept_memcpy_indirect.cc
new file mode 100644
index 000000000000..c5f44df3faaf
--- /dev/null
+++ b/test/asan/TestCases/Windows/dll_intercept_memcpy_indirect.cc
@@ -0,0 +1,34 @@
+// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t
+// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll
+// RUN: not %run %t %t.dll 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <string.h>
+
+void call_memcpy(void* (*f)(void *, const void *, size_t),
+ void *a, const void *b, size_t c) {
+ f(a, b, c);
+}
+
+extern "C" __declspec(dllexport)
+int test_function() {
+ char buff1[6] = "Hello", buff2[5];
+
+ call_memcpy(&memcpy, buff2, buff1, 5);
+ if (buff1[2] != buff2[2])
+ return 2;
+ printf("Initial test OK\n");
+ fflush(0);
+// CHECK: Initial test OK
+
+ call_memcpy(&memcpy, buff2, buff1, 6);
+// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 6 at [[ADDR]] thread T0
+// CHECK-NEXT: __asan_{{.*}}memcpy
+// CHECK-NEXT: call_memcpy
+// CHECK-NEXT: test_function {{.*}}dll_intercept_memcpy_indirect.cc:[[@LINE-5]]
+// CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} in frame
+// CHECK-NEXT: test_function {{.*}}dll_intercept_memcpy_indirect.cc
+// CHECK: 'buff2' <== Memory access at offset {{.*}} overflows this variable
+ return 0;
+}
diff --git a/test/asan/TestCases/Windows/dll_intercept_memset.cc b/test/asan/TestCases/Windows/dll_intercept_memset.cc
new file mode 100644
index 000000000000..d4be376f2458
--- /dev/null
+++ b/test/asan/TestCases/Windows/dll_intercept_memset.cc
@@ -0,0 +1,32 @@
+// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t
+// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll
+// RUN: not %run %t %t.dll 2>&1 | FileCheck %s
+
+// Test that it works correctly even with ICF enabled.
+// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll -link /OPT:REF /OPT:ICF
+// RUN: not %run %t %t.dll 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <string.h>
+
+extern "C" __declspec(dllexport)
+int test_function() {
+ char buff[5] = "aaaa";
+
+ memset(buff, 'b', 5);
+ if (buff[2] != 'b')
+ return 2;
+ printf("Initial test OK\n");
+ fflush(0);
+// CHECK: Initial test OK
+
+ memset(buff, 'c', 6);
+// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 6 at [[ADDR]] thread T0
+// CHECK-NEXT: __asan_memset
+// CHECK-NEXT: test_function {{.*}}dll_intercept_memset.cc:[[@LINE-4]]
+// CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} in frame
+// CHECK-NEXT: test_function {{.*}}dll_intercept_memset.cc
+// CHECK: 'buff' <== Memory access at offset {{.*}} overflows this variable
+ return 0;
+}
diff --git a/test/asan/TestCases/Windows/dll_intercept_strlen.cc b/test/asan/TestCases/Windows/dll_intercept_strlen.cc
new file mode 100644
index 000000000000..f41d47858bee
--- /dev/null
+++ b/test/asan/TestCases/Windows/dll_intercept_strlen.cc
@@ -0,0 +1,28 @@
+// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t
+// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll
+// RUN: not %run %t %t.dll 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <string.h>
+
+extern "C" __declspec(dllexport)
+int test_function() {
+ char str[] = "Hello!";
+ if (6 != strlen(str))
+ return 1;
+ printf("Initial test OK\n");
+ fflush(0);
+// CHECK: Initial test OK
+
+ str[6] = '!'; // Removes '\0' at the end!
+ int len = strlen(str);
+// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// FIXME: Should be READ of size 1, see issue 155.
+// CHECK: READ of size {{[0-9]+}} at [[ADDR]] thread T0
+// CHECK-NEXT: {{#0 .*}}strlen
+// CHECK-NEXT: {{#1 .* test_function .*}}dll_intercept_strlen.cc:[[@LINE-5]]
+//
+// CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} in frame
+// CHECK-NEXT: test_function {{.*}}dll_intercept_strlen.cc:
+ return len > 42;
+}
diff --git a/test/asan/TestCases/Windows/dll_large_function.cc b/test/asan/TestCases/Windows/dll_large_function.cc
new file mode 100644
index 000000000000..039d01f84ba5
--- /dev/null
+++ b/test/asan/TestCases/Windows/dll_large_function.cc
@@ -0,0 +1,12 @@
+// Make sure we can link a DLL with large functions which would mean
+// functions such as __asan_loadN and __asan_storeN will be called
+// from the DLL. We simulate the large function with
+// -mllvm -asan-instrumentation-with-call-threshold=0.
+// RUN: %clang_cl_asan %s -c -Fo%t.obj -mllvm -asan-instrumentation-with-call-threshold=0
+// RUN: link /nologo /DLL /OUT:%t.dll %t.obj %asan_dll_thunk
+// REQUIRES: asan-static-runtime
+
+void f(long* foo, long* bar) {
+ // One load and one store
+ *foo = *bar;
+}
diff --git a/test/asan/TestCases/Windows/dll_malloc_left_oob.cc b/test/asan/TestCases/Windows/dll_malloc_left_oob.cc
new file mode 100644
index 000000000000..0653ea45f6ef
--- /dev/null
+++ b/test/asan/TestCases/Windows/dll_malloc_left_oob.cc
@@ -0,0 +1,23 @@
+// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t
+// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll
+// RUN: not %run %t %t.dll 2>&1 | FileCheck %s
+
+#include <malloc.h>
+extern "C" __declspec(dllexport)
+int test_function() {
+ char *buffer = (char*)malloc(42);
+ buffer[-1] = 42;
+// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 1 at [[ADDR]] thread T0
+// CHECK-NEXT: test_function {{.*}}dll_malloc_left_oob.cc:[[@LINE-3]]
+// CHECK-NEXT: main {{.*}}dll_host.cc
+//
+// CHECK: [[ADDR]] is located 1 bytes to the left of 42-byte region
+// CHECK-LABEL: allocated by thread T0 here:
+// CHECK-NEXT: malloc
+// CHECK-NEXT: test_function {{.*}}dll_malloc_left_oob.cc:[[@LINE-10]]
+// CHECK-NEXT: main {{.*}}dll_host.cc
+// CHECK-LABEL: SUMMARY
+ free(buffer);
+ return 0;
+}
diff --git a/test/asan/TestCases/Windows/dll_malloc_uaf.cc b/test/asan/TestCases/Windows/dll_malloc_uaf.cc
new file mode 100644
index 000000000000..b286380ac445
--- /dev/null
+++ b/test/asan/TestCases/Windows/dll_malloc_uaf.cc
@@ -0,0 +1,28 @@
+// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t
+// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll
+// RUN: not %run %t %t.dll 2>&1 | FileCheck %s
+
+#include <malloc.h>
+
+extern "C" __declspec(dllexport)
+int test_function() {
+ int *buffer = (int*)malloc(42);
+ free(buffer);
+ buffer[0] = 42;
+// CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 4 at [[ADDR]] thread T0
+// CHECK-NEXT: test_function {{.*}}dll_malloc_uaf.cc:[[@LINE-3]]
+// CHECK-NEXT: main {{.*}}dll_host
+//
+// CHECK: [[ADDR]] is located 0 bytes inside of 42-byte region
+// CHECK-LABEL: freed by thread T0 here:
+// CHECK-NEXT: free
+// CHECK-NEXT: test_function {{.*}}dll_malloc_uaf.cc:[[@LINE-10]]
+// CHECK-NEXT: main {{.*}}dll_host
+//
+// CHECK-LABEL: previously allocated by thread T0 here:
+// CHECK-NEXT: malloc
+// CHECK-NEXT: test_function {{.*}}dll_malloc_uaf.cc:[[@LINE-16]]
+// CHECK-NEXT: main {{.*}}dll_host
+ return 0;
+}
diff --git a/test/asan/TestCases/Windows/dll_noreturn.cc b/test/asan/TestCases/Windows/dll_noreturn.cc
new file mode 100644
index 000000000000..6ec90725145f
--- /dev/null
+++ b/test/asan/TestCases/Windows/dll_noreturn.cc
@@ -0,0 +1,28 @@
+// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t
+// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll
+// RUN: not %run %t %t.dll 2>&1 | FileCheck %s
+
+#include <process.h>
+
+void noreturn_f() {
+ int subscript = -1;
+ char buffer[42];
+ buffer[subscript] = 42;
+ _exit(1);
+// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 1 at [[ADDR]] thread T0
+// CHECK-NEXT: noreturn_f {{.*}}dll_noreturn.cc:[[@LINE-4]]
+// CHECK-NEXT: test_function {{.*}}dll_noreturn.cc
+// CHECK-NEXT: main {{.*}}dll_host.cc
+//
+// CHECK: Address [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:.*]] in frame
+// CHECK-NEXT: noreturn_f {{.*}}dll_noreturn.cc
+// CHECK: 'buffer' <== Memory access at offset [[OFFSET]] underflows this variable
+// CHECK-LABEL: SUMMARY
+}
+
+extern "C" __declspec(dllexport)
+int test_function() {
+ noreturn_f();
+ return 0;
+}
diff --git a/test/asan/TestCases/Windows/dll_null_deref.cc b/test/asan/TestCases/Windows/dll_null_deref.cc
new file mode 100644
index 000000000000..0fb18de29163
--- /dev/null
+++ b/test/asan/TestCases/Windows/dll_null_deref.cc
@@ -0,0 +1,18 @@
+// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t
+// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll
+// RUN: not %run %t %t.dll 2>&1 | FileCheck %s
+
+__attribute__((noinline))
+static void NullDeref(int *ptr) {
+ // CHECK: ERROR: AddressSanitizer: access-violation on unknown address
+ // CHECK: {{0x0*000.. .*pc 0x.*}}
+ ptr[10]++; // BOOM
+}
+
+extern "C" __declspec(dllexport)
+int test_function() {
+ NullDeref((int*)0);
+ // CHECK: {{ #1 0x.* in test_function .*\dll_null_deref.cc:}}[[@LINE-1]]
+ // CHECK: AddressSanitizer can not provide additional info.
+ return 0;
+}
diff --git a/test/asan/TestCases/Windows/dll_operator_array_new_left_oob.cc b/test/asan/TestCases/Windows/dll_operator_array_new_left_oob.cc
new file mode 100644
index 000000000000..736ce80cc32a
--- /dev/null
+++ b/test/asan/TestCases/Windows/dll_operator_array_new_left_oob.cc
@@ -0,0 +1,25 @@
+// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t
+// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll
+// RUN: not %run %t %t.dll 2>&1 | FileCheck %s
+
+extern "C" __declspec(dllexport)
+int test_function() {
+ char *buffer = new char[42];
+ buffer[-1] = 42;
+// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 1 at [[ADDR]] thread T0
+// CHECK-NEXT: test_function {{.*}}dll_operator_array_new_left_oob.cc:[[@LINE-3]]
+// CHECK-NEXT: main {{.*}}dll_host.cc
+//
+// CHECK: [[ADDR]] is located 1 bytes to the left of 42-byte region
+// CHECK-LABEL: allocated by thread T0 here:
+// FIXME: Should get rid of the malloc/free frames called from the inside of
+// operator new/delete in DLLs when using -MT CRT.
+// FIXME: The 'operator new' frame should have [].
+// CHECK: operator new
+// CHECK-NEXT: test_function {{.*}}dll_operator_array_new_left_oob.cc:[[@LINE-13]]
+// CHECK-NEXT: main {{.*}}dll_host.cc
+// CHECK-LABEL: SUMMARY
+ delete [] buffer;
+ return 0;
+}
diff --git a/test/asan/TestCases/Windows/dll_operator_array_new_with_dtor_left_oob.cc b/test/asan/TestCases/Windows/dll_operator_array_new_with_dtor_left_oob.cc
new file mode 100644
index 000000000000..8306a737bfff
--- /dev/null
+++ b/test/asan/TestCases/Windows/dll_operator_array_new_with_dtor_left_oob.cc
@@ -0,0 +1,33 @@
+// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t
+// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll
+// RUN: not %run %t %t.dll 2>&1 | FileCheck %s
+
+struct C {
+ int x;
+ ~C() {}
+};
+
+extern "C" __declspec(dllexport)
+int test_function() {
+ C *buffer = new C[42];
+ buffer[-2].x = 42;
+// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 4 at [[ADDR]] thread T0
+// CHECK-NEXT: test_function {{.*}}dll_operator_array_new_with_dtor_left_oob.cc:[[@LINE-3]]
+// CHECK-NEXT: main {{.*}}dll_host.cc
+//
+// FIXME: Currently it says "4 bytes ... left of 172-byte region",
+// should be "8 bytes ... left of 168-byte region", see
+// https://code.google.com/p/address-sanitizer/issues/detail?id=314
+// CHECK: [[ADDR]] is located {{.*}} bytes to the left of 172-byte region
+// FIXME: Should get rid of the malloc/free frames called from the inside of
+// operator new/delete in DLLs when using -MT CRT.
+// FIXME: The operator new frame should have [].
+// CHECK-LABEL: allocated by thread T0 here:
+// CHECK: operator new
+// CHECK-NEXT: test_function {{.*}}dll_operator_array_new_with_dtor_left_oob.cc:[[@LINE-16]]
+// CHECK-NEXT: main {{.*}}dll_host.cc
+// CHECK-LABEL: SUMMARY
+ delete [] buffer;
+ return 0;
+}
diff --git a/test/asan/TestCases/Windows/dll_poison_unpoison.cc b/test/asan/TestCases/Windows/dll_poison_unpoison.cc
new file mode 100644
index 000000000000..d486cb122251
--- /dev/null
+++ b/test/asan/TestCases/Windows/dll_poison_unpoison.cc
@@ -0,0 +1,35 @@
+// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t
+// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll
+// RUN: not %run %t %t.dll 2>&1 | FileCheck %s
+
+#include <sanitizer/asan_interface.h>
+
+void should_not_crash(volatile char *c) {
+ *c = 42;
+}
+
+void should_crash(volatile char *c) {
+ *c = 42;
+}
+
+extern "C" __declspec(dllexport)
+int test_function() {
+ char buffer[256];
+ should_not_crash(&buffer[0]);
+ __asan_poison_memory_region(buffer, 128);
+ should_not_crash(&buffer[192]);
+ __asan_unpoison_memory_region(buffer, 64);
+ should_not_crash(&buffer[32]);
+
+ should_crash(&buffer[96]);
+// CHECK: AddressSanitizer: use-after-poison on address [[ADDR:0x[0-9a-f]+]]
+// CHECK-NEXT: WRITE of size 1 at [[ADDR]] thread T0
+// CHECK-NEXT: should_crash {{.*}}\dll_poison_unpoison.cc
+// CHECK-NEXT: test_function {{.*}}\dll_poison_unpoison.cc:[[@LINE-4]]
+// CHECK-NEXT: main
+//
+// CHECK: [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:.*]] in frame
+// CHECK-NEXT: test_function {{.*}}\dll_poison_unpoison.cc
+// CHECK: 'buffer' <== Memory access at offset [[OFFSET]] is inside this variable
+ return 0;
+}
diff --git a/test/asan/TestCases/Windows/dll_seh.cc b/test/asan/TestCases/Windows/dll_seh.cc
new file mode 100644
index 000000000000..6e4c724e504d
--- /dev/null
+++ b/test/asan/TestCases/Windows/dll_seh.cc
@@ -0,0 +1,60 @@
+// 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: %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: %run %t %t.dll
+
+#include <windows.h>
+#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();
+
+#if !defined(__clang__)
+__declspec(noinline)
+void Throw() {
+ int local, zero = 0;
+ fprintf(stderr, "Throw: %p\n", &local);
+ local = 5 / zero;
+}
+
+__declspec(noinline)
+void ThrowAndCatch() {
+ int local;
+ __try {
+ Throw();
+ } __except(EXCEPTION_EXECUTE_HANDLER) {
+ fprintf(stderr, "__except: %p\n", &local);
+ }
+}
+#else
+
+extern "C" __declspec(dllexport)
+int test_function() {
+ 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));
+ return 0;
+}
+#endif
diff --git a/test/asan/TestCases/Windows/dll_stack_use_after_return.cc b/test/asan/TestCases/Windows/dll_stack_use_after_return.cc
new file mode 100644
index 000000000000..6cd74c265b8f
--- /dev/null
+++ b/test/asan/TestCases/Windows/dll_stack_use_after_return.cc
@@ -0,0 +1,28 @@
+// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t
+// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll
+// RUN: env ASAN_OPTIONS=detect_stack_use_after_return=1 not %run %t %t.dll 2>&1 | FileCheck %s
+
+#include <malloc.h>
+
+char *x;
+
+void foo() {
+ char stack_buffer[42];
+ x = &stack_buffer[13];
+}
+
+extern "C" __declspec(dllexport)
+int test_function() {
+ foo();
+ *x = 42;
+// CHECK: AddressSanitizer: stack-use-after-return
+// CHECK: WRITE of size 1 at [[ADDR:.*]] thread T0
+// CHECK-NEXT: test_function {{.*}}dll_stack_use_after_return.cc:[[@LINE-3]]
+// CHECK-NEXT: main
+//
+// CHECK: Address [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:.*]] in frame
+// CHECK-NEXT: #0 {{.*}} foo {{.*}}dll_stack_use_after_return.cc
+// CHECK: 'stack_buffer' <== Memory access at offset [[OFFSET]] is inside this variable
+ return 0;
+}
+
diff --git a/test/asan/TestCases/Windows/dll_thread_stack_array_left_oob.cc b/test/asan/TestCases/Windows/dll_thread_stack_array_left_oob.cc
new file mode 100644
index 000000000000..8f53623419ce
--- /dev/null
+++ b/test/asan/TestCases/Windows/dll_thread_stack_array_left_oob.cc
@@ -0,0 +1,36 @@
+// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t
+// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll
+// RUN: not %run %t %t.dll 2>&1 | FileCheck %s
+
+#include <windows.h>
+#include <malloc.h>
+
+DWORD WINAPI thread_proc(void *context) {
+ int subscript = -1;
+ char stack_buffer[42];
+ stack_buffer[subscript] = 42;
+// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 1 at [[ADDR]] thread T1
+// CHECK-NEXT: thread_proc {{.*}}dll_thread_stack_array_left_oob.cc:[[@LINE-3]]
+//
+// CHECK: Address [[ADDR]] is located in stack of thread T1 at offset [[OFFSET:.*]] in frame
+// CHECK-NEXT: thread_proc {{.*}}dll_thread_stack_array_left_oob.cc
+//
+// CHECK: 'stack_buffer' <== Memory access at offset [[OFFSET]] underflows this variable
+
+ return 0;
+}
+
+extern "C" __declspec(dllexport)
+int test_function() {
+ HANDLE thr = CreateThread(NULL, 0, thread_proc, NULL, 0, NULL);
+// CHECK-LABEL: Thread T1 created by T0 here:
+// CHECK: test_function {{.*}}dll_thread_stack_array_left_oob.cc:[[@LINE-2]]
+// CHECK-NEXT: main {{.*}}dll_host.cc
+// CHECK-LABEL: SUMMARY
+ if (thr == 0)
+ return 1;
+ if (WAIT_OBJECT_0 != WaitForSingleObject(thr, INFINITE))
+ return 2;
+ return 0;
+}
diff --git a/test/asan/TestCases/Windows/double_free.cc b/test/asan/TestCases/Windows/double_free.cc
new file mode 100644
index 000000000000..18a9fcb44a75
--- /dev/null
+++ b/test/asan/TestCases/Windows/double_free.cc
@@ -0,0 +1,21 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <malloc.h>
+
+int main() {
+ int *x = (int*)malloc(42 * sizeof(int));
+ free(x);
+ free(x);
+// CHECK: AddressSanitizer: attempting double-free on [[ADDR:0x[0-9a-f]+]]
+// CHECK-NEXT: {{#0 .* free }}
+// CHECK-NEXT: {{#1 .* main .*double_free.cc}}:[[@LINE-3]]
+// CHECK: [[ADDR]] is located 0 bytes inside of 168-byte region
+// CHECK-LABEL: freed by thread T0 here:
+// CHECK-NEXT: {{#0 .* free }}
+// CHECK-NEXT: {{#1 .* main .*double_free.cc}}:[[@LINE-8]]
+// CHECK-LABEL: previously allocated by thread T0 here:
+// CHECK-NEXT: {{#0 .* malloc }}
+// CHECK-NEXT: {{#1 .* main .*double_free.cc}}:[[@LINE-12]]
+ return 0;
+}
diff --git a/test/asan/TestCases/Windows/double_operator_delete.cc b/test/asan/TestCases/Windows/double_operator_delete.cc
new file mode 100644
index 000000000000..eae4a64c2b92
--- /dev/null
+++ b/test/asan/TestCases/Windows/double_operator_delete.cc
@@ -0,0 +1,25 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <malloc.h>
+
+int main() {
+ int *x = new int[42];
+ delete [] x;
+ delete [] x;
+// CHECK: AddressSanitizer: attempting double-free on [[ADDR:0x[0-9a-f]+]]
+// FIXME: The 'operator delete' frame should have [].
+// CHECK-NEXT: {{#0 .* operator delete}}
+// CHECK-NEXT: {{#1 .* main .*double_operator_delete.cc}}:[[@LINE-4]]
+// CHECK: [[ADDR]] is located 0 bytes inside of 168-byte region
+// CHECK-LABEL: freed by thread T0 here:
+// FIXME: The 'operator delete' frame should have [].
+// CHECK-NEXT: {{#0 .* operator delete}}
+// CHECK-NEXT: {{#1 .* main .*double_operator_delete.cc}}:[[@LINE-10]]
+// CHECK-LABEL: previously allocated by thread T0 here:
+// FIXME: The 'operator new' frame should have [].
+// CHECK-NEXT: {{#0 .* operator new}}
+// CHECK-NEXT: {{#1 .* main .*double_operator_delete.cc}}:[[@LINE-15]]
+ return 0;
+}
+
diff --git a/test/asan/TestCases/Windows/global_const_string.cc b/test/asan/TestCases/Windows/global_const_string.cc
new file mode 100644
index 000000000000..8c147c917c88
--- /dev/null
+++ b/test/asan/TestCases/Windows/global_const_string.cc
@@ -0,0 +1,12 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: %run %t | FileCheck %s
+
+#include <windows.h>
+#include <stdio.h>
+
+int main(void) {
+ static const char *foo = "foobarspam";
+ printf("Global string is `%s`\n", foo);
+// CHECK: Global string is `foobarspam`
+ return 0;
+}
diff --git a/test/asan/TestCases/Windows/global_const_string_oob.cc b/test/asan/TestCases/Windows/global_const_string_oob.cc
new file mode 100644
index 000000000000..b39e3dbb3b4e
--- /dev/null
+++ b/test/asan/TestCases/Windows/global_const_string_oob.cc
@@ -0,0 +1,20 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <windows.h>
+#include <stdio.h>
+
+extern "C" const char *foo = "foobarspam";
+
+int main(void) {
+ if (foo[16])
+ printf("Boo\n");
+// CHECK-NOT: Boo
+// CHECK: AddressSanitizer: global-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: READ of size 1 at [[ADDR]] thread T0
+// CHECK-NEXT: {{#0 .* main .*global_const_string_oob.cc:}}[[@LINE-5]]
+// CHECK: [[ADDR]] is located 5 bytes to the right of global variable [[STR:.*]] defined in {{'.*global_const_string_oob.cc:7:.*' .*}} of size 11
+// CHECK: [[STR]] is ascii string 'foobarspam'
+ return 0;
+}
+
diff --git a/test/asan/TestCases/Windows/hello_world.cc b/test/asan/TestCases/Windows/hello_world.cc
new file mode 100644
index 000000000000..400ca1b3eacc
--- /dev/null
+++ b/test/asan/TestCases/Windows/hello_world.cc
@@ -0,0 +1,9 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: %run %t | FileCheck %s
+
+#include <stdio.h>
+
+int main() {
+ printf("Hello, world!\n");
+// CHECK: Hello, world!
+}
diff --git a/test/asan/TestCases/Windows/intercept_memcpy.cc b/test/asan/TestCases/Windows/intercept_memcpy.cc
new file mode 100644
index 000000000000..9ee984b1873d
--- /dev/null
+++ b/test/asan/TestCases/Windows/intercept_memcpy.cc
@@ -0,0 +1,31 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <string.h>
+
+void call_memcpy(void* (*f)(void *, const void *, size_t),
+ void *a, const void *b, size_t c) {
+ f(a, b, c);
+}
+
+int main() {
+ char buff1[6] = "Hello", buff2[5];
+
+ call_memcpy(&memcpy, buff2, buff1, 5);
+ if (buff1[2] != buff2[2])
+ return 2;
+ printf("Initial test OK\n");
+ fflush(0);
+// CHECK: Initial test OK
+
+ call_memcpy(&memcpy, buff2, buff1, 6);
+// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 6 at [[ADDR]] thread T0
+// CHECK-NEXT: __asan_{{.*}}memcpy
+// CHECK-NEXT: call_memcpy
+// CHECK-NEXT: main {{.*}}intercept_memcpy.cc:[[@LINE-5]]
+// CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} in frame
+// CHECK-NEXT: #0 {{.*}} main
+// CHECK: 'buff2' <== Memory access at offset {{.*}} overflows this variable
+}
diff --git a/test/asan/TestCases/Windows/intercept_strdup.cc b/test/asan/TestCases/Windows/intercept_strdup.cc
new file mode 100644
index 000000000000..edb1f2f99245
--- /dev/null
+++ b/test/asan/TestCases/Windows/intercept_strdup.cc
@@ -0,0 +1,27 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <string.h>
+#include <malloc.h>
+
+int main() {
+ char *ptr = _strdup("Hello");
+ int subscript = 1;
+ ptr[subscript] = '3';
+ printf("%s\n", ptr);
+ fflush(0);
+// CHECK: H3llo
+
+ subscript = -1;
+ ptr[subscript] = 42;
+// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 1 at [[ADDR]] thread T0
+// 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 }}
+// CHECK: {{#1 .*strdup}}
+// CHECK: {{#2 .* main .*}}intercept_strdup.cc:[[@LINE-16]]
+ free(ptr);
+}
diff --git a/test/asan/TestCases/Windows/intercept_strlen.cc b/test/asan/TestCases/Windows/intercept_strlen.cc
new file mode 100644
index 000000000000..928a286bedfa
--- /dev/null
+++ b/test/asan/TestCases/Windows/intercept_strlen.cc
@@ -0,0 +1,27 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <string.h>
+
+int main() {
+ char str[] = "Hello";
+ if (5 != strlen(str))
+ return 1;
+
+ printf("Initial test OK\n");
+ fflush(0);
+// CHECK: Initial test OK
+
+ str[5] = '!'; // Losing '\0' at the end.
+ int len = strlen(str);
+// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// FIXME: Should be READ of size 1, see issue 155.
+// CHECK: READ of size {{[0-9]+}} at [[ADDR]] thread T0
+// CHECK: strlen
+// CHECK-NEXT: main {{.*}}intercept_strlen.cc:[[@LINE-5]]
+// CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} in frame
+// CHECK-NEXT: main {{.*}}intercept_strlen.cc
+// CHECK: 'str' <== Memory access at offset {{.*}} overflows this variable
+ return len < 6;
+}
diff --git a/test/asan/TestCases/Windows/lit.local.cfg b/test/asan/TestCases/Windows/lit.local.cfg
new file mode 100644
index 000000000000..13ef6d428251
--- /dev/null
+++ b/test/asan/TestCases/Windows/lit.local.cfg
@@ -0,0 +1,14 @@
+def getRoot(config):
+ if not config.parent:
+ return config
+ return getRoot(config.parent)
+
+root = getRoot(config)
+
+# We only run a small set of tests on Windows for now.
+# Override the parent directory's "unsupported" decision until we can handle
+# all of its tests.
+if root.host_os in ['Windows']:
+ config.unsupported = False
+else:
+ config.unsupported = True
diff --git a/test/asan/TestCases/Windows/longjmp.cc b/test/asan/TestCases/Windows/longjmp.cc
new file mode 100644
index 000000000000..443933e8ab62
--- /dev/null
+++ b/test/asan/TestCases/Windows/longjmp.cc
@@ -0,0 +1,26 @@
+// RUN: %clangxx_asan -O %s -o %t && %run %t
+
+// FIXME: merge this with the common longjmp test when we can run common
+// tests on Windows.
+
+#include <assert.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <sanitizer/asan_interface.h>
+
+static jmp_buf buf;
+
+int main() {
+ char x[32];
+ fprintf(stderr, "\nTestLongJmp\n");
+ fprintf(stderr, "Before: %p poisoned: %d\n", &x,
+ __asan_address_is_poisoned(x + 32));
+ assert(__asan_address_is_poisoned(x + 32));
+ if (0 == setjmp(buf))
+ longjmp(buf, 1);
+ 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));
+}
diff --git a/test/asan/TestCases/Windows/malloc_left_oob.cc b/test/asan/TestCases/Windows/malloc_left_oob.cc
new file mode 100644
index 000000000000..ec133c393da2
--- /dev/null
+++ b/test/asan/TestCases/Windows/malloc_left_oob.cc
@@ -0,0 +1,17 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <malloc.h>
+
+int main() {
+ char *buffer = (char*)malloc(42);
+ buffer[-1] = 42;
+// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 1 at [[ADDR]] thread T0
+// CHECK-NEXT: {{#0 .* main .*malloc_left_oob.cc}}:[[@LINE-3]]
+// CHECK: [[ADDR]] is located 1 bytes to the left of 42-byte region
+// CHECK: allocated by thread T0 here:
+// CHECK-NEXT: {{#0 .* malloc }}
+// CHECK-NEXT: {{#1 .* main .*malloc_left_oob.cc}}:[[@LINE-8]]
+ free(buffer);
+}
diff --git a/test/asan/TestCases/Windows/malloc_right_oob.cc b/test/asan/TestCases/Windows/malloc_right_oob.cc
new file mode 100644
index 000000000000..9975316d3e02
--- /dev/null
+++ b/test/asan/TestCases/Windows/malloc_right_oob.cc
@@ -0,0 +1,17 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <malloc.h>
+
+int main() {
+ char *buffer = (char*)malloc(42);
+ buffer[42] = 42;
+// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 1 at [[ADDR]] thread T0
+// CHECK-NEXT: {{#0 .* main .*malloc_right_oob.cc}}:[[@LINE-3]]
+// CHECK: [[ADDR]] is located 0 bytes to the right of 42-byte region
+// CHECK: allocated by thread T0 here:
+// CHECK-NEXT: {{#0 .* malloc }}
+// CHECK-NEXT: {{#1 .* main .*malloc_right_oob.cc}}:[[@LINE-8]]
+ free(buffer);
+}
diff --git a/test/asan/TestCases/Windows/malloc_uaf.cc b/test/asan/TestCases/Windows/malloc_uaf.cc
new file mode 100644
index 000000000000..f58478947bf4
--- /dev/null
+++ b/test/asan/TestCases/Windows/malloc_uaf.cc
@@ -0,0 +1,20 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <malloc.h>
+
+int main() {
+ char *buffer = (char*)malloc(42);
+ free(buffer);
+ buffer[0] = 42;
+// CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 1 at [[ADDR]] thread T0
+// CHECK-NEXT: {{#0 .* main .*malloc_uaf.cc}}:[[@LINE-3]]
+// CHECK: [[ADDR]] is located 0 bytes inside of 42-byte region
+// CHECK: freed by thread T0 here:
+// CHECK-NEXT: {{#0 .* free }}
+// CHECK-NEXT: {{#1 .* main .*malloc_uaf.cc}}:[[@LINE-8]]
+// CHECK: previously allocated by thread T0 here:
+// CHECK-NEXT: {{#0 .* malloc }}
+// CHECK-NEXT: {{#1 .* main .*malloc_uaf.cc}}:[[@LINE-12]]
+}
diff --git a/test/asan/TestCases/Windows/null_deref.cc b/test/asan/TestCases/Windows/null_deref.cc
new file mode 100644
index 000000000000..202000f59db7
--- /dev/null
+++ b/test/asan/TestCases/Windows/null_deref.cc
@@ -0,0 +1,15 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// FIXME: merge this with the common null_deref test when we can run common
+// tests on Windows.
+
+__attribute__((noinline))
+static void NullDeref(int *ptr) {
+ // CHECK: ERROR: AddressSanitizer: access-violation on unknown address
+ // CHECK: {{0x0*000.. .*pc 0x.*}}
+ ptr[10]++; // BOOM
+}
+int main() {
+ NullDeref((int*)0);
+ // CHECK: {{ #1 0x.* in main.*null_deref.cc:}}[[@LINE-1]]
+ // CHECK: AddressSanitizer can not provide additional info.
+}
diff --git a/test/asan/TestCases/Windows/null_deref_multiple_dlls.cc b/test/asan/TestCases/Windows/null_deref_multiple_dlls.cc
new file mode 100644
index 000000000000..62fe544ae545
--- /dev/null
+++ b/test/asan/TestCases/Windows/null_deref_multiple_dlls.cc
@@ -0,0 +1,40 @@
+// Make sure everything works even if the main module doesn't have any stack
+// variables, thus doesn't explicitly reference any symbol exported by the
+// runtime thunk.
+//
+// RUN: %clang_cl_asan -LD -O0 -DDLL1 %s -Fe%t1.dll
+// RUN: %clang_cl_asan -LD -O0 -DDLL2 %s -Fe%t2.dll
+// RUN: %clang_cl_asan -O0 -DEXE %s %t1.lib %t2.lib -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <malloc.h>
+#include <string.h>
+
+extern "C" {
+#if defined(EXE)
+__declspec(dllimport) void foo1();
+__declspec(dllimport) void foo2();
+
+int main() {
+ foo1();
+ foo2();
+}
+#elif defined(DLL1)
+__declspec(dllexport) void foo1() {}
+#elif defined(DLL2)
+__attribute__((noinline))
+static void NullDeref(int *ptr) {
+ // CHECK: ERROR: AddressSanitizer: access-violation on unknown address
+ // CHECK: {{0x0*000.. .*pc 0x.*}}
+ ptr[10]++; // BOOM
+}
+
+__declspec(dllexport) void foo2() {
+ NullDeref((int*)0);
+ // CHECK: {{ #1 0x.* in foo2.*null_deref_multiple_dlls.cc:}}[[@LINE-1]]
+ // CHECK: AddressSanitizer can not provide additional info.
+}
+#else
+# error oops!
+#endif
+}
diff --git a/test/asan/TestCases/Windows/operator_array_new_left_oob.cc b/test/asan/TestCases/Windows/operator_array_new_left_oob.cc
new file mode 100644
index 000000000000..20a0f1927e5b
--- /dev/null
+++ b/test/asan/TestCases/Windows/operator_array_new_left_oob.cc
@@ -0,0 +1,17 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+int main() {
+ char *buffer = new char[42];
+ buffer[-1] = 42;
+// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 1 at [[ADDR]] thread T0
+// CHECK-NEXT: {{#0 .* main .*operator_array_new_left_oob.cc}}:[[@LINE-3]]
+//
+// CHECK: [[ADDR]] is located 1 bytes to the left of 42-byte region
+// CHECK-LABEL: allocated by thread T0 here:
+// FIXME: The 'operator new' frame should have [].
+// CHECK-NEXT: {{#0 .* operator new}}
+// CHECK-NEXT: {{#1 .* main .*operator_array_new_left_oob.cc}}:[[@LINE-10]]
+ delete [] buffer;
+}
diff --git a/test/asan/TestCases/Windows/operator_array_new_right_oob.cc b/test/asan/TestCases/Windows/operator_array_new_right_oob.cc
new file mode 100644
index 000000000000..23775ef6066e
--- /dev/null
+++ b/test/asan/TestCases/Windows/operator_array_new_right_oob.cc
@@ -0,0 +1,18 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <windows.h>
+
+int main() {
+ char *buffer = new char[42];
+ buffer[42] = 42;
+// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 1 at [[ADDR]] thread T0
+// CHECK: {{#0 .* main .*operator_array_new_right_oob.cc}}:[[@LINE-3]]
+// CHECK: [[ADDR]] is located 0 bytes to the right of 42-byte region
+// CHECK: allocated by thread T0 here:
+// FIXME: The 'operator new' frame should have [].
+// CHECK: {{#0 .* operator new}}
+// CHECK: {{#1 .* main .*operator_array_new_right_oob.cc}}:[[@LINE-9]]
+ delete [] buffer;
+}
diff --git a/test/asan/TestCases/Windows/operator_array_new_uaf.cc b/test/asan/TestCases/Windows/operator_array_new_uaf.cc
new file mode 100644
index 000000000000..b638ef1df415
--- /dev/null
+++ b/test/asan/TestCases/Windows/operator_array_new_uaf.cc
@@ -0,0 +1,24 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <windows.h>
+
+int main() {
+ char *buffer = new char[42];
+ delete [] buffer;
+ buffer[0] = 42;
+// CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 1 at [[ADDR]] thread T0
+// CHECK: {{#0 .* main .*operator_array_new_uaf.cc}}:[[@LINE-3]]
+// CHECK: [[ADDR]] is located 0 bytes inside of 42-byte region
+// CHECK-LABEL: freed by thread T0 here:
+// FIXME: The 'operator delete' frame should have [].
+// CHECK: {{#0 .* operator delete}}
+// CHECK: {{#1 .* main .*operator_array_new_uaf.cc}}:[[@LINE-9]]
+// CHECK-LABEL: previously allocated by thread T0 here:
+// FIXME: The 'operator new' frame should have [].
+// CHECK: {{#0 .* operator new}}
+// CHECK: {{#1 .* main .*operator_array_new_uaf.cc}}:[[@LINE-14]]
+ return 0;
+}
+
diff --git a/test/asan/TestCases/Windows/operator_array_new_with_dtor_left_oob.cc b/test/asan/TestCases/Windows/operator_array_new_with_dtor_left_oob.cc
new file mode 100644
index 000000000000..63f2929bd89b
--- /dev/null
+++ b/test/asan/TestCases/Windows/operator_array_new_with_dtor_left_oob.cc
@@ -0,0 +1,25 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+struct C {
+ int x;
+ ~C() {}
+};
+
+int main() {
+ C *buffer = new C[42];
+ buffer[-2].x = 42;
+// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 4 at [[ADDR]] thread T0
+// CHECK-NEXT: {{#0 .* main .*operator_array_new_with_dtor_left_oob.cc}}:[[@LINE-3]]
+//
+// FIXME: Currently it says "4 bytes ... left of 172-byte region",
+// should be "8 bytes ... left of 168-byte region", see
+// https://code.google.com/p/address-sanitizer/issues/detail?id=314
+// CHECK: [[ADDR]] is located {{.*}} bytes to the left of 172-byte region
+// CHECK-LABEL: allocated by thread T0 here:
+// FIXME: The 'operator new' frame should have [].
+// CHECK-NEXT: {{#0 .* operator new}}
+// CHECK-NEXT: {{#1 .* main .*operator_array_new_with_dtor_left_oob.cc}}:[[@LINE-13]]
+ delete [] buffer;
+}
diff --git a/test/asan/TestCases/Windows/operator_delete_wrong_argument.cc b/test/asan/TestCases/Windows/operator_delete_wrong_argument.cc
new file mode 100644
index 000000000000..c3e7daca55b0
--- /dev/null
+++ b/test/asan/TestCases/Windows/operator_delete_wrong_argument.cc
@@ -0,0 +1,12 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <windows.h>
+
+int main() {
+ int *x = new int[42];
+ delete (x + 1);
+// CHECK: AddressSanitizer: attempting free on address which was not malloc()-ed
+// CHECK: {{#0 0x.* operator delete }}
+// CHECK: {{#1 .* main .*operator_delete_wrong_argument.cc}}:[[@LINE-3]]
+}
diff --git a/test/asan/TestCases/Windows/operator_new_left_oob.cc b/test/asan/TestCases/Windows/operator_new_left_oob.cc
new file mode 100644
index 000000000000..c077f11d68f9
--- /dev/null
+++ b/test/asan/TestCases/Windows/operator_new_left_oob.cc
@@ -0,0 +1,17 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <windows.h>
+
+int main() {
+ char *buffer = new char;
+ buffer[-1] = 42;
+// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 1 at [[ADDR]] thread T0
+// CHECK: {{#0 .* main .*operator_new_left_oob.cc}}:[[@LINE-3]]
+// CHECK: [[ADDR]] is located 1 bytes to the left of 1-byte region
+// CHECK: allocated by thread T0 here:
+// CHECK: {{#0 .* operator new }}
+// CHECK: {{#1 .* main .*operator_new_left_oob.cc}}:[[@LINE-8]]
+ delete buffer;
+}
diff --git a/test/asan/TestCases/Windows/operator_new_right_oob.cc b/test/asan/TestCases/Windows/operator_new_right_oob.cc
new file mode 100644
index 000000000000..7a66d1714b97
--- /dev/null
+++ b/test/asan/TestCases/Windows/operator_new_right_oob.cc
@@ -0,0 +1,17 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <windows.h>
+
+int main() {
+ char *buffer = new char;
+ buffer[1] = 42;
+// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 1 at [[ADDR]] thread T0
+// CHECK: {{#0 .* main .*operator_new_right_oob.cc}}:[[@LINE-3]]
+// CHECK: [[ADDR]] is located 0 bytes to the right of 1-byte region
+// CHECK: allocated by thread T0 here:
+// CHECK: {{#0 .* operator new }}
+// CHECK: {{#1 .* main .*operator_new_right_oob.cc}}:[[@LINE-8]]
+ delete buffer;
+}
diff --git a/test/asan/TestCases/Windows/operator_new_uaf.cc b/test/asan/TestCases/Windows/operator_new_uaf.cc
new file mode 100644
index 000000000000..c435458f0c1c
--- /dev/null
+++ b/test/asan/TestCases/Windows/operator_new_uaf.cc
@@ -0,0 +1,22 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <windows.h>
+
+int main() {
+ char *buffer = new char;
+ delete buffer;
+ *buffer = 42;
+// CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 1 at [[ADDR]] thread T0
+// CHECK: {{#0 .* main .*operator_new_uaf.cc}}:[[@LINE-3]]
+// CHECK: [[ADDR]] is located 0 bytes inside of 1-byte region
+// CHECK-LABEL: freed by thread T0 here:
+// CHECK: {{#0 .* operator delete }}
+// CHECK: {{#1 .* main .*operator_new_uaf.cc}}:[[@LINE-8]]
+// CHECK-LABEL: previously allocated by thread T0 here:
+// CHECK: {{#0 .* operator new }}
+// CHECK: {{#1 .* main .*operator_new_uaf.cc}}:[[@LINE-12]]
+ return 0;
+}
+
diff --git a/test/asan/TestCases/Windows/realloc_left_oob.cc b/test/asan/TestCases/Windows/realloc_left_oob.cc
new file mode 100644
index 000000000000..7d30e1d5c4ad
--- /dev/null
+++ b/test/asan/TestCases/Windows/realloc_left_oob.cc
@@ -0,0 +1,17 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <malloc.h>
+
+int main() {
+ char *buffer = (char*)realloc(0, 42);
+ buffer[-1] = 42;
+// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 1 at [[ADDR]] thread T0
+// CHECK-NEXT: {{#0 .* main .*realloc_left_oob.cc}}:[[@LINE-3]]
+// CHECK: [[ADDR]] is located 1 bytes to the left of 42-byte region
+// CHECK: allocated by thread T0 here:
+// CHECK-NEXT: {{#0 .* realloc }}
+// CHECK-NEXT: {{#1 .* main .*realloc_left_oob.cc}}:[[@LINE-8]]
+ free(buffer);
+}
diff --git a/test/asan/TestCases/Windows/realloc_right_oob.cc b/test/asan/TestCases/Windows/realloc_right_oob.cc
new file mode 100644
index 000000000000..f741390bd4e9
--- /dev/null
+++ b/test/asan/TestCases/Windows/realloc_right_oob.cc
@@ -0,0 +1,17 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <malloc.h>
+
+int main() {
+ char *buffer = (char*)realloc(0, 42);
+ buffer[42] = 42;
+// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 1 at [[ADDR]] thread T0
+// CHECK-NEXT: {{#0 .* main .*realloc_right_oob.cc}}:[[@LINE-3]]
+// CHECK: [[ADDR]] is located 0 bytes to the right of 42-byte region
+// CHECK: allocated by thread T0 here:
+// CHECK-NEXT: {{#0 .* realloc }}
+// CHECK-NEXT: {{#1 .* main .*realloc_right_oob.cc}}:[[@LINE-8]]
+ free(buffer);
+}
diff --git a/test/asan/TestCases/Windows/realloc_uaf.cc b/test/asan/TestCases/Windows/realloc_uaf.cc
new file mode 100644
index 000000000000..c5b6953cf76a
--- /dev/null
+++ b/test/asan/TestCases/Windows/realloc_uaf.cc
@@ -0,0 +1,20 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <malloc.h>
+
+int main() {
+ char *buffer = (char*)realloc(0, 42);
+ free(buffer);
+ buffer[0] = 42;
+// CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 1 at [[ADDR]] thread T0
+// CHECK-NEXT: {{#0 .* main .*realloc_uaf.cc}}:[[@LINE-3]]
+// CHECK: [[ADDR]] is located 0 bytes inside of 42-byte region
+// CHECK: freed by thread T0 here:
+// CHECK-NEXT: {{#0 .* free }}
+// CHECK-NEXT: {{#1 .* main .*realloc_uaf.cc}}:[[@LINE-8]]
+// CHECK: previously allocated by thread T0 here:
+// CHECK-NEXT: {{#0 .* realloc }}
+// CHECK-NEXT: {{#1 .* main .*realloc_uaf.cc}}:[[@LINE-12]]
+}
diff --git a/test/asan/TestCases/Windows/report_after_syminitialize.cc b/test/asan/TestCases/Windows/report_after_syminitialize.cc
new file mode 100644
index 000000000000..faf5e35db5f5
--- /dev/null
+++ b/test/asan/TestCases/Windows/report_after_syminitialize.cc
@@ -0,0 +1,19 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+#include <windows.h>
+#include <dbghelp.h>
+
+int main() {
+ // Make sure the RTL recovers from "no options enabled" dbghelp setup.
+ SymSetOptions(0);
+
+ // Make sure the RTL recovers from "fInvadeProcess=FALSE".
+ if (!SymInitialize(GetCurrentProcess(), 0, FALSE))
+ return 42;
+
+ *(volatile int*)0 = 42;
+ // CHECK: ERROR: AddressSanitizer: access-violation on unknown address
+ // CHECK-NEXT: {{WARNING: .*DbgHelp}}
+ // CHECK: {{#0 0x.* in main.*report_after_syminitialize.cc:}}[[@LINE-3]]
+ // CHECK: AddressSanitizer can not provide additional info.
+}
diff --git a/test/asan/TestCases/Windows/seh.cc b/test/asan/TestCases/Windows/seh.cc
new file mode 100644
index 000000000000..50cf6ddba8d6
--- /dev/null
+++ b/test/asan/TestCases/Windows/seh.cc
@@ -0,0 +1,56 @@
+// 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".
+//
+// Check both -GS and -GS- builds:
+// RUN: cl -c %s -Fo%t.obj
+// RUN: %clangxx_asan -o %t.exe %s %t.obj
+// RUN: %run %t.exe
+//
+// RUN: cl -GS- -c %s -Fo%t.obj
+// RUN: %clangxx_asan -o %t.exe %s %t.obj
+// RUN: %run %t.exe
+
+#include <windows.h>
+#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();
+
+#if !defined(__clang__)
+__declspec(noinline)
+void Throw() {
+ int local, zero = 0;
+ fprintf(stderr, "Throw: %p\n", &local);
+ local = 5 / zero;
+}
+
+__declspec(noinline)
+void ThrowAndCatch() {
+ int local;
+ __try {
+ Throw();
+ } __except(EXCEPTION_EXECUTE_HANDLER) {
+ fprintf(stderr, "__except: %p\n", &local);
+ }
+}
+#else
+
+int main() {
+ 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));
+}
+#endif
diff --git a/test/asan/TestCases/Windows/stack_array_left_oob.cc b/test/asan/TestCases/Windows/stack_array_left_oob.cc
new file mode 100644
index 000000000000..040d855b48e2
--- /dev/null
+++ b/test/asan/TestCases/Windows/stack_array_left_oob.cc
@@ -0,0 +1,16 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+
+int main() {
+ int subscript = -1;
+ char buffer[42];
+ buffer[subscript] = 42;
+// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 1 at [[ADDR]] thread T0
+// CHECK-NEXT: {{#0 .* main .*stack_array_left_oob.cc}}:[[@LINE-3]]
+// CHECK: Address [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:.*]] in frame
+// CHECK-NEXT: {{#0 .* main .*stack_array_left_oob.cc}}
+// CHECK: 'buffer' <== Memory access at offset [[OFFSET]] underflows this variable
+}
diff --git a/test/asan/TestCases/Windows/stack_array_right_oob.cc b/test/asan/TestCases/Windows/stack_array_right_oob.cc
new file mode 100644
index 000000000000..a370246aa072
--- /dev/null
+++ b/test/asan/TestCases/Windows/stack_array_right_oob.cc
@@ -0,0 +1,16 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+
+int main() {
+ int subscript = 42;
+ char buffer[42];
+ buffer[subscript] = 42;
+// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 1 at [[ADDR]] thread T0
+// CHECK-NEXT: {{#0 .* main .*stack_array_right_oob.cc}}:[[@LINE-3]]
+// CHECK: Address [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:.*]] in frame
+// CHECK-NEXT: {{#0 .* main .*stack_array_right_oob.cc}}
+// CHECK: 'buffer' <== Memory access at offset [[OFFSET]] overflows this variable
+}
diff --git a/test/asan/TestCases/Windows/stack_array_sanity.cc b/test/asan/TestCases/Windows/stack_array_sanity.cc
new file mode 100644
index 000000000000..1aef1a923d24
--- /dev/null
+++ b/test/asan/TestCases/Windows/stack_array_sanity.cc
@@ -0,0 +1,12 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: %run %t | FileCheck %s
+
+#include <stdio.h>
+
+int main() {
+ int subscript = 1;
+ char buffer[42];
+ buffer[subscript] = 42;
+ printf("OK\n");
+// CHECK: OK
+}
diff --git a/test/asan/TestCases/Windows/stack_use_after_return.cc b/test/asan/TestCases/Windows/stack_use_after_return.cc
new file mode 100644
index 000000000000..7955f2685308
--- /dev/null
+++ b/test/asan/TestCases/Windows/stack_use_after_return.cc
@@ -0,0 +1,22 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: env ASAN_OPTIONS=detect_stack_use_after_return=1 not %run %t 2>&1 | FileCheck %s
+
+char *x;
+
+void foo() {
+ char stack_buffer[42];
+ x = &stack_buffer[13];
+}
+
+int main() {
+ foo();
+ *x = 42;
+// CHECK: AddressSanitizer: stack-use-after-return
+// CHECK: WRITE of size 1 at {{.*}} thread T0
+// CHECK-NEXT: {{#0 0x.* in main .*stack_use_after_return.cc}}:[[@LINE-3]]
+//
+// CHECK: is located in stack of thread T0 at offset [[OFFSET:.*]] in frame
+// CHECK-NEXT: {{#0 0x.* in foo .*stack_use_after_return.cc}}
+//
+// CHECK: 'stack_buffer' <== Memory access at offset [[OFFSET]] is inside this variable
+}
diff --git a/test/asan/TestCases/Windows/thread_simple.cc b/test/asan/TestCases/Windows/thread_simple.cc
new file mode 100644
index 000000000000..14bb82f042aa
--- /dev/null
+++ b/test/asan/TestCases/Windows/thread_simple.cc
@@ -0,0 +1,26 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: %run %t
+
+#include <windows.h>
+
+DWORD WINAPI thread_proc(void *) {
+ volatile char stack_buffer[42];
+ for (int i = 0; i < sizeof(stack_buffer); ++i)
+ stack_buffer[i] = 42;
+ return 0x42;
+}
+
+int main() {
+ DWORD exitcode;
+ HANDLE thr = CreateThread(NULL, 0, thread_proc, NULL, 0, NULL);
+ if (thr == 0)
+ return 1;
+ if (WAIT_OBJECT_0 != WaitForSingleObject(thr, INFINITE))
+ return 2;
+
+ GetExitCodeThread(thr, &exitcode);
+ if (exitcode != 0x42)
+ return 3;
+ CloseHandle(thr);
+}
+
diff --git a/test/asan/TestCases/Windows/thread_stack_array_left_oob.cc b/test/asan/TestCases/Windows/thread_stack_array_left_oob.cc
new file mode 100644
index 000000000000..17b9b1bf8ecb
--- /dev/null
+++ b/test/asan/TestCases/Windows/thread_stack_array_left_oob.cc
@@ -0,0 +1,27 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <windows.h>
+
+DWORD WINAPI thread_proc(void *) {
+ int subscript = -1;
+ volatile char stack_buffer[42];
+ stack_buffer[subscript] = 42;
+// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 1 at [[ADDR]] thread T1
+// CHECK: {{#0 .* thread_proc .*thread_stack_array_left_oob.cc}}:[[@LINE-3]]
+// CHECK: Address [[ADDR]] is located in stack of thread T1 at offset {{.*}} in frame
+// CHECK: thread_proc
+ return 0;
+}
+
+int main() {
+ HANDLE thr = CreateThread(NULL, 0, thread_proc, NULL, 0, NULL);
+// CHECK: Thread T1 created by T0 here:
+// CHECK: {{#[01] .* main .*thread_stack_array_left_oob.cc}}:[[@LINE-2]]
+
+ // A failure to create a thread should fail the test!
+ if (thr == 0) return 0;
+
+ WaitForSingleObject(thr, INFINITE);
+}
diff --git a/test/asan/TestCases/Windows/thread_stack_array_right_oob.cc b/test/asan/TestCases/Windows/thread_stack_array_right_oob.cc
new file mode 100644
index 000000000000..601a1b8a8760
--- /dev/null
+++ b/test/asan/TestCases/Windows/thread_stack_array_right_oob.cc
@@ -0,0 +1,27 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <windows.h>
+
+DWORD WINAPI thread_proc(void *) {
+ int subscript = 42;
+ volatile char stack_buffer[42];
+ stack_buffer[subscript] = 42;
+// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 1 at [[ADDR]] thread T1
+// CHECK: {{#0 .* thread_proc .*thread_stack_array_right_oob.cc}}:[[@LINE-3]]
+// CHECK: Address [[ADDR]] is located in stack of thread T1 at offset {{.*}} in frame
+// CHECK: thread_proc
+ return 0;
+}
+
+int main(void) {
+ HANDLE thr = CreateThread(NULL, 0, thread_proc, NULL, 0, NULL);
+// CHECK: Thread T1 created by T0 here:
+// CHECK: {{#[01] .* main .*thread_stack_array_right_oob.cc}}:[[@LINE-2]]
+
+ // A failure to create a thread should fail the test!
+ if (thr == 0) return 0;
+
+ WaitForSingleObject(thr, INFINITE);
+}
diff --git a/test/asan/TestCases/Windows/thread_stack_reuse.cc b/test/asan/TestCases/Windows/thread_stack_reuse.cc
new file mode 100644
index 000000000000..7da3a807dac1
--- /dev/null
+++ b/test/asan/TestCases/Windows/thread_stack_reuse.cc
@@ -0,0 +1,37 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: %run %t
+
+#include <windows.h>
+
+DWORD WINAPI thread_proc_1(void *) {
+ volatile int x, y, z;
+ x = 1;
+ y = 2;
+ z = 3;
+ return 0;
+}
+
+DWORD WINAPI thread_proc_2(void *) {
+ volatile char stack_buffer[42];
+ for (int i = 0; i < sizeof(stack_buffer); ++i)
+ stack_buffer[i] = 42;
+ return 0;
+}
+
+int main(void) {
+ HANDLE thr = NULL;
+
+ thr = CreateThread(NULL, 0, thread_proc_1, NULL, 0, NULL);
+ if (thr == 0)
+ return 1;
+ if (WAIT_OBJECT_0 != WaitForSingleObject(thr, INFINITE))
+ return 2;
+
+ thr = CreateThread(NULL, 0, thread_proc_2, NULL, 0, NULL);
+ if (thr == 0)
+ return 3;
+ if (WAIT_OBJECT_0 != WaitForSingleObject(thr, INFINITE))
+ return 4;
+ CloseHandle(thr);
+}
+
diff --git a/test/asan/TestCases/Windows/thread_stress.cc b/test/asan/TestCases/Windows/thread_stress.cc
new file mode 100644
index 000000000000..74be8d88c665
--- /dev/null
+++ b/test/asan/TestCases/Windows/thread_stress.cc
@@ -0,0 +1,30 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: %run %t
+
+#include <windows.h>
+
+DWORD WINAPI thread_proc(void *) {
+ volatile char stack_buffer[42];
+ for (int i = 0; i < sizeof(stack_buffer); ++i)
+ stack_buffer[i] = 42;
+ return 0;
+}
+
+int main(void) {
+ for (int iter = 0; iter < 1024; ++iter) {
+ const int NUM_THREADS = 8;
+ HANDLE thr[NUM_THREADS];
+ for (int i = 0; i < NUM_THREADS; ++i) {
+ thr[i] = CreateThread(NULL, 0, thread_proc, NULL, 0, NULL);
+ if (thr[i] == 0)
+ return 1;
+ }
+ for (int i = 0; i < NUM_THREADS; ++i) {
+ if (WAIT_OBJECT_0 != WaitForSingleObject(thr[i], INFINITE))
+ return 2;
+ CloseHandle(thr[i]);
+ }
+ }
+ return 0;
+}
+
diff --git a/test/asan/TestCases/Windows/throw_catch.cc b/test/asan/TestCases/Windows/throw_catch.cc
new file mode 100644
index 000000000000..5313d25b26d6
--- /dev/null
+++ b/test/asan/TestCases/Windows/throw_catch.cc
@@ -0,0 +1,73 @@
+// 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/Windows/use_after_realloc.cc b/test/asan/TestCases/Windows/use_after_realloc.cc
new file mode 100644
index 000000000000..9d2c025258fa
--- /dev/null
+++ b/test/asan/TestCases/Windows/use_after_realloc.cc
@@ -0,0 +1,23 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <malloc.h>
+
+int main() {
+ char *buffer = (char*)realloc(0, 32),
+ *stale = buffer;
+ buffer = (char*)realloc(buffer, 64);
+ // The 'stale' may now point to a free'd memory.
+ stale[0] = 42;
+// CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 1 at [[ADDR]] thread T0
+// CHECK-NEXT: {{#0 .* main .*use_after_realloc.cc}}:[[@LINE-3]]
+// CHECK: [[ADDR]] is located 0 bytes inside of 32-byte region
+// CHECK: freed by thread T0 here:
+// CHECK-NEXT: {{#0 .* realloc }}
+// CHECK-NEXT: {{#1 .* main .*use_after_realloc.cc}}:[[@LINE-9]]
+// CHECK: previously allocated by thread T0 here:
+// CHECK-NEXT: {{#0 .* realloc }}
+// CHECK-NEXT: {{#1 .* main .*use_after_realloc.cc}}:[[@LINE-14]]
+ free(buffer);
+}
diff --git a/test/asan/TestCases/Windows/use_after_return_linkage.cc b/test/asan/TestCases/Windows/use_after_return_linkage.cc
new file mode 100644
index 000000000000..48c5065a0fa9
--- /dev/null
+++ b/test/asan/TestCases/Windows/use_after_return_linkage.cc
@@ -0,0 +1,12 @@
+// Make sure LIBCMT doesn't accidentally get added to the list of DEFAULTLIB
+// directives. REQUIRES: asan-dynamic-runtime
+// RUN: %clang_cl_asan -LD %s | FileCheck %s
+// CHECK: Creating library
+// CHECK-NOT: LIBCMT
+
+void foo(int *p) { *p = 42; }
+
+__declspec(dllexport) void bar() {
+ int x;
+ foo(&x);
+}
diff --git a/test/asan/TestCases/Windows/windows_h.cc b/test/asan/TestCases/Windows/windows_h.cc
new file mode 100644
index 000000000000..40cf5a10ad4f
--- /dev/null
+++ b/test/asan/TestCases/Windows/windows_h.cc
@@ -0,0 +1,7 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: %run %t
+
+// Just make sure we can parse <windows.h>
+#include <windows.h>
+
+int main() {}
diff --git a/test/asan/TestCases/Windows/wrong_downcast_on_heap.cc b/test/asan/TestCases/Windows/wrong_downcast_on_heap.cc
new file mode 100644
index 000000000000..112dd5308d11
--- /dev/null
+++ b/test/asan/TestCases/Windows/wrong_downcast_on_heap.cc
@@ -0,0 +1,26 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+class Parent {
+ public:
+ int field;
+};
+
+class Child : public Parent {
+ public:
+ int extra_field;
+};
+
+int main(void) {
+ Parent *p = new Parent;
+ Child *c = (Child*)p; // Intentional error here!
+ c->extra_field = 42;
+// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 4 at [[ADDR]] thread T0
+// CHECK: {{#0 0x[0-9a-f]* in main .*wrong_downcast_on_heap.cc}}:[[@LINE-3]]
+// CHECK: [[ADDR]] is located 0 bytes to the right of 4-byte region
+// CHECK: allocated by thread T0 here:
+// CHECK: #0 {{.*}} operator new
+ return 0;
+}
+
diff --git a/test/asan/TestCases/Windows/wrong_downcast_on_stack.cc b/test/asan/TestCases/Windows/wrong_downcast_on_stack.cc
new file mode 100644
index 000000000000..2859ecc521d2
--- /dev/null
+++ b/test/asan/TestCases/Windows/wrong_downcast_on_stack.cc
@@ -0,0 +1,26 @@
+// RUN: %clang_cl_asan -O0 %s -Fe%t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+class Parent {
+ public:
+ int field;
+};
+
+class Child : public Parent {
+ public:
+ int extra_field;
+};
+
+int main(void) {
+ Parent p;
+ Child *c = (Child*)&p; // Intentional error here!
+ c->extra_field = 42;
+// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 4 at [[ADDR]] thread T0
+// CHECK-NEXT: {{#0 0x[0-9a-f]* in main .*wrong_downcast_on_stack.cc}}:[[@LINE-3]]
+// CHECK: [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:[0-9]+]] in frame
+// CHECK-NEXT: {{#0 0x[0-9a-f]* in main }}
+// CHECK: 'p' <== Memory access at offset [[OFFSET]] overflows this variable
+ return 0;
+}
+
diff --git a/test/asan/TestCases/alloca_big_alignment.cc b/test/asan/TestCases/alloca_big_alignment.cc
new file mode 100644
index 000000000000..2ede3f949b24
--- /dev/null
+++ b/test/asan/TestCases/alloca_big_alignment.cc
@@ -0,0 +1,18 @@
+// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-allocas %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+//
+
+#include <assert.h>
+
+__attribute__((noinline)) void foo(int index, int len) {
+ volatile char str[len] __attribute__((aligned(128)));
+ assert(!(reinterpret_cast<long>(str) & 127L));
+ str[index] = '1'; // BOOM
+// CHECK: ERROR: AddressSanitizer: dynamic-stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 1 at [[ADDR]] thread T0
+}
+
+int main(int argc, char **argv) {
+ foo(10, 10);
+ return 0;
+}
diff --git a/test/asan/TestCases/alloca_detect_custom_size_.cc b/test/asan/TestCases/alloca_detect_custom_size_.cc
new file mode 100644
index 000000000000..2b0f573de3d0
--- /dev/null
+++ b/test/asan/TestCases/alloca_detect_custom_size_.cc
@@ -0,0 +1,23 @@
+// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-allocas %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+//
+
+#include <assert.h>
+
+struct A {
+ char a[3];
+ int b[3];
+};
+
+__attribute__((noinline)) void foo(int index, int len) {
+ volatile struct A str[len] __attribute__((aligned(32)));
+ assert(!(reinterpret_cast<long>(str) & 31L));
+ str[index].a[0] = '1'; // BOOM
+// CHECK: ERROR: AddressSanitizer: dynamic-stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 1 at [[ADDR]] thread T0
+}
+
+int main(int argc, char **argv) {
+ foo(10, 10);
+ return 0;
+}
diff --git a/test/asan/TestCases/alloca_instruments_all_paddings.cc b/test/asan/TestCases/alloca_instruments_all_paddings.cc
new file mode 100644
index 000000000000..d60a3b22dcb9
--- /dev/null
+++ b/test/asan/TestCases/alloca_instruments_all_paddings.cc
@@ -0,0 +1,23 @@
+// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-allocas %s -o %t
+// RUN: %run %t 2>&1
+//
+
+#include "sanitizer/asan_interface.h"
+#include <assert.h>
+
+__attribute__((noinline)) void foo(int index, int len) {
+ volatile char str[len] __attribute__((aligned(32)));
+ assert(!(reinterpret_cast<long>(str) & 31L));
+ char *q = (char *)__asan_region_is_poisoned((char *)str, 64);
+ assert(q && ((q - str) == index));
+}
+
+int main(int argc, char **argv) {
+ for (int i = 1; i < 33; ++i)
+ foo(i, i);
+
+ for (int i = 1; i < 33; ++i)
+ foo(i, i);
+
+ return 0;
+}
diff --git a/test/asan/TestCases/alloca_overflow_partial.cc b/test/asan/TestCases/alloca_overflow_partial.cc
new file mode 100644
index 000000000000..590f35465dad
--- /dev/null
+++ b/test/asan/TestCases/alloca_overflow_partial.cc
@@ -0,0 +1,18 @@
+// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-allocas %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+//
+
+#include <assert.h>
+
+__attribute__((noinline)) void foo(int index, int len) {
+ volatile char str[len] __attribute__((aligned(32)));
+ assert(!(reinterpret_cast<long>(str) & 31L));
+ str[index] = '1'; // BOOM
+// CHECK: ERROR: AddressSanitizer: dynamic-stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 1 at [[ADDR]] thread T0
+}
+
+int main(int argc, char **argv) {
+ foo(10, 10);
+ return 0;
+}
diff --git a/test/asan/TestCases/alloca_overflow_right.cc b/test/asan/TestCases/alloca_overflow_right.cc
new file mode 100644
index 000000000000..caec846838ef
--- /dev/null
+++ b/test/asan/TestCases/alloca_overflow_right.cc
@@ -0,0 +1,18 @@
+// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-allocas %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+//
+
+#include <assert.h>
+
+__attribute__((noinline)) void foo(int index, int len) {
+ volatile char str[len] __attribute__((aligned(32)));
+ assert(!(reinterpret_cast<long>(str) & 31L));
+ str[index] = '1'; // BOOM
+// CHECK: ERROR: AddressSanitizer: dynamic-stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 1 at [[ADDR]] thread T0
+}
+
+int main(int argc, char **argv) {
+ foo(33, 10);
+ return 0;
+}
diff --git a/test/asan/TestCases/alloca_safe_access.cc b/test/asan/TestCases/alloca_safe_access.cc
new file mode 100644
index 000000000000..240454fd55e4
--- /dev/null
+++ b/test/asan/TestCases/alloca_safe_access.cc
@@ -0,0 +1,17 @@
+// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-allocas %s -o %t
+// RUN: %run %t 2>&1
+//
+
+#include <assert.h>
+
+__attribute__((noinline)) void foo(int index, int len) {
+ volatile char str[len] __attribute__((aligned(32)));
+ assert(!(reinterpret_cast<long>(str) & 31L));
+ str[index] = '1';
+}
+
+int main(int argc, char **argv) {
+ foo(4, 5);
+ foo(39, 40);
+ return 0;
+}
diff --git a/test/asan/TestCases/alloca_underflow_left.cc b/test/asan/TestCases/alloca_underflow_left.cc
new file mode 100644
index 000000000000..6e7061f7cfe2
--- /dev/null
+++ b/test/asan/TestCases/alloca_underflow_left.cc
@@ -0,0 +1,18 @@
+// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-allocas %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+//
+
+#include <assert.h>
+
+__attribute__((noinline)) void foo(int index, int len) {
+ volatile char str[len] __attribute__((aligned(32)));
+ assert(!(reinterpret_cast<long>(str) & 31L));
+ str[index] = '1'; // BOOM
+// CHECK: ERROR: AddressSanitizer: dynamic-stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// CHECK: WRITE of size 1 at [[ADDR]] thread T0
+}
+
+int main(int argc, char **argv) {
+ foo(-1, 10);
+ return 0;
+}
diff --git a/test/asan/TestCases/allocator_returns_null.cc b/test/asan/TestCases/allocator_returns_null.cc
new file mode 100644
index 000000000000..59a053c3dcad
--- /dev/null
+++ b/test/asan/TestCases/allocator_returns_null.cc
@@ -0,0 +1,83 @@
+// Test the behavior of malloc/calloc/realloc when the allocation size is huge.
+// By default (allocator_may_return_null=0) the process should crash.
+// With allocator_may_return_null=1 the allocator should return 0.
+//
+// RUN: %clangxx_asan -O0 %s -o %t
+// RUN: not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
+// RUN: env ASAN_OPTIONS=allocator_may_return_null=0 not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
+// RUN: env ASAN_OPTIONS=allocator_may_return_null=1 %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mNULL
+// RUN: env ASAN_OPTIONS=allocator_may_return_null=0 not %run %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cCRASH
+// RUN: env ASAN_OPTIONS=allocator_may_return_null=1 %run %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cNULL
+// RUN: env ASAN_OPTIONS=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coCRASH
+// RUN: env ASAN_OPTIONS=allocator_may_return_null=1 %run %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coNULL
+// RUN: env ASAN_OPTIONS=allocator_may_return_null=0 not %run %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rCRASH
+// RUN: env ASAN_OPTIONS=allocator_may_return_null=1 %run %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rNULL
+// RUN: env ASAN_OPTIONS=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrCRASH
+// RUN: env ASAN_OPTIONS=allocator_may_return_null=1 %run %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrNULL
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <limits>
+int main(int argc, char **argv) {
+ volatile size_t size = std::numeric_limits<size_t>::max() - 10000;
+ assert(argc == 2);
+ char *x = 0;
+ if (!strcmp(argv[1], "malloc")) {
+ fprintf(stderr, "malloc:\n");
+ x = (char*)malloc(size);
+ }
+ if (!strcmp(argv[1], "calloc")) {
+ fprintf(stderr, "calloc:\n");
+ x = (char*)calloc(size / 4, 4);
+ }
+
+ if (!strcmp(argv[1], "calloc-overflow")) {
+ fprintf(stderr, "calloc-overflow:\n");
+ volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max();
+ size_t kArraySize = 4096;
+ volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
+ x = (char*)calloc(kArraySize, kArraySize2);
+ }
+
+ if (!strcmp(argv[1], "realloc")) {
+ fprintf(stderr, "realloc:\n");
+ x = (char*)realloc(0, size);
+ }
+ if (!strcmp(argv[1], "realloc-after-malloc")) {
+ fprintf(stderr, "realloc-after-malloc:\n");
+ char *t = (char*)malloc(100);
+ *t = 42;
+ x = (char*)realloc(t, size);
+ assert(*t == 42);
+ free(t);
+ }
+ // The NULL pointer is printed differently on different systems, while (long)0
+ // is always the same.
+ fprintf(stderr, "x: %lx\n", (long)x);
+ free(x);
+ return x != 0;
+}
+// CHECK-mCRASH: malloc:
+// CHECK-mCRASH: AddressSanitizer's allocator is terminating the process
+// CHECK-cCRASH: calloc:
+// CHECK-cCRASH: AddressSanitizer's allocator is terminating the process
+// CHECK-coCRASH: calloc-overflow:
+// CHECK-coCRASH: AddressSanitizer's allocator is terminating the process
+// CHECK-rCRASH: realloc:
+// CHECK-rCRASH: AddressSanitizer's allocator is terminating the process
+// CHECK-mrCRASH: realloc-after-malloc:
+// CHECK-mrCRASH: AddressSanitizer's allocator is terminating the process
+
+// CHECK-mNULL: malloc:
+// CHECK-mNULL: x: 0
+// CHECK-cNULL: calloc:
+// CHECK-cNULL: x: 0
+// CHECK-coNULL: calloc-overflow:
+// CHECK-coNULL: x: 0
+// CHECK-rNULL: realloc:
+// CHECK-rNULL: x: 0
+// CHECK-mrNULL: realloc-after-malloc:
+// CHECK-mrNULL: x: 0
diff --git a/test/asan/TestCases/asan_and_llvm_coverage_test.cc b/test/asan/TestCases/asan_and_llvm_coverage_test.cc
new file mode 100644
index 000000000000..35bdfcb353c2
--- /dev/null
+++ b/test/asan/TestCases/asan_and_llvm_coverage_test.cc
@@ -0,0 +1,10 @@
+// RUN: %clangxx_asan -coverage -O0 %s -o %t
+// RUN: env ASAN_OPTIONS=check_initialization_order=1 %run %t 2>&1 | FileCheck %s
+// XFAIL: android
+#include <stdio.h>
+int foo() { return 1; }
+int XXX = foo();
+int main() {
+ printf("PASS\n");
+// CHECK: PASS
+}
diff --git a/test/asan/TestCases/atexit_stats.cc b/test/asan/TestCases/atexit_stats.cc
new file mode 100644
index 000000000000..be6534475245
--- /dev/null
+++ b/test/asan/TestCases/atexit_stats.cc
@@ -0,0 +1,18 @@
+// Make sure we report atexit stats.
+// RUN: %clangxx_asan -O3 %s -o %t
+// RUN: env ASAN_OPTIONS=atexit=1:print_stats=1 %run %t 2>&1 | FileCheck %s
+//
+// No atexit output on Android due to
+// https://code.google.com/p/address-sanitizer/issues/detail?id=263
+// XFAIL: android
+
+#include <stdlib.h>
+#if !defined(__APPLE__) && !defined(__FreeBSD__)
+#include <malloc.h>
+#endif
+int *p1 = (int*)malloc(900);
+int *p2 = (int*)malloc(90000);
+int *p3 = (int*)malloc(9000000);
+int main() { }
+
+// CHECK: AddressSanitizer exit stats:
diff --git a/test/asan/TestCases/blacklist.cc b/test/asan/TestCases/blacklist.cc
new file mode 100644
index 000000000000..7c31484c2174
--- /dev/null
+++ b/test/asan/TestCases/blacklist.cc
@@ -0,0 +1,38 @@
+// Test the blacklist functionality of ASan
+
+// RUN: echo "fun:*brokenFunction*" > %tmp
+// RUN: echo "global:*badGlobal*" >> %tmp
+// RUN: echo "src:*blacklist-extra.cc" >> %tmp
+// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -O0 %s -o %t \
+// RUN: %p/Helpers/blacklist-extra.cc && %run %t 2>&1
+// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -O1 %s -o %t \
+// RUN: %p/Helpers/blacklist-extra.cc && %run %t 2>&1
+// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -O2 %s -o %t \
+// RUN: %p/Helpers/blacklist-extra.cc && %run %t 2>&1
+// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -O3 %s -o %t \
+// RUN: %p/Helpers/blacklist-extra.cc && %run %t 2>&1
+
+// badGlobal is accessed improperly, but we blacklisted it. Align
+// it to make sure memory past the end of badGlobal will be in
+// the same page.
+__attribute__((aligned(16))) int badGlobal;
+int readBadGlobal() {
+ return (&badGlobal)[1];
+}
+
+// A function which is broken, but excluded in the blacklist.
+int brokenFunction(int argc) {
+ char x[10] = {0};
+ return x[argc * 10]; // BOOM
+}
+
+// This function is defined in Helpers/blacklist-extra.cc, a source file which
+// is blacklisted by name
+int externalBrokenFunction(int x);
+
+int main(int argc, char **argv) {
+ brokenFunction(argc);
+ int x = readBadGlobal();
+ externalBrokenFunction(argc);
+ return 0;
+}
diff --git a/test/asan/TestCases/contiguous_container.cc b/test/asan/TestCases/contiguous_container.cc
new file mode 100644
index 000000000000..0f3a7db5b060
--- /dev/null
+++ b/test/asan/TestCases/contiguous_container.cc
@@ -0,0 +1,75 @@
+// RUN: %clangxx_asan -O %s -o %t && %run %t
+//
+// Test __sanitizer_annotate_contiguous_container.
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <sanitizer/asan_interface.h>
+
+void TestContainer(size_t capacity) {
+ char *beg = new char[capacity];
+ char *end = beg + capacity;
+ char *mid = beg + capacity;
+ char *old_mid = 0;
+
+ for (int i = 0; i < 10000; i++) {
+ size_t size = rand() % (capacity + 1);
+ assert(size <= capacity);
+ old_mid = mid;
+ mid = beg + size;
+ __sanitizer_annotate_contiguous_container(beg, end, old_mid, mid);
+
+ for (size_t idx = 0; idx < size; idx++)
+ assert(!__asan_address_is_poisoned(beg + idx));
+ for (size_t idx = size; idx < capacity; idx++)
+ assert(__asan_address_is_poisoned(beg + idx));
+ assert(__sanitizer_verify_contiguous_container(beg, mid, end));
+ if (mid != beg)
+ assert(!__sanitizer_verify_contiguous_container(beg, mid - 1, end));
+ if (mid != end)
+ assert(!__sanitizer_verify_contiguous_container(beg, mid + 1, end));
+ }
+
+ // Don't forget to unpoison the whole thing before destroing/reallocating.
+ __sanitizer_annotate_contiguous_container(beg, end, mid, end);
+ for (size_t idx = 0; idx < capacity; idx++)
+ assert(!__asan_address_is_poisoned(beg + idx));
+ delete[] beg;
+}
+
+__attribute__((noinline))
+void Throw() { throw 1; }
+
+__attribute__((noinline))
+void ThrowAndCatch() {
+ try {
+ Throw();
+ } catch(...) {
+ }
+}
+
+void TestThrow() {
+ char x[32];
+ __sanitizer_annotate_contiguous_container(x, x + 32, x + 32, x + 14);
+ assert(!__asan_address_is_poisoned(x + 13));
+ assert(__asan_address_is_poisoned(x + 14));
+ ThrowAndCatch();
+ assert(!__asan_address_is_poisoned(x + 13));
+ // FIXME: invert the assertion below once we fix
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=258
+ // This assertion works only w/o UAR.
+ if (!__asan_get_current_fake_stack())
+ assert(!__asan_address_is_poisoned(x + 14));
+ __sanitizer_annotate_contiguous_container(x, x + 32, x + 14, x + 32);
+ assert(!__asan_address_is_poisoned(x + 13));
+ assert(!__asan_address_is_poisoned(x + 14));
+}
+
+int main(int argc, char **argv) {
+ int n = argc == 1 ? 128 : atoi(argv[1]);
+ for (int i = 0; i <= n; i++)
+ TestContainer(i);
+ TestThrow();
+}
diff --git a/test/asan/TestCases/contiguous_container_crash.cc b/test/asan/TestCases/contiguous_container_crash.cc
new file mode 100644
index 000000000000..143ae9d8edee
--- /dev/null
+++ b/test/asan/TestCases/contiguous_container_crash.cc
@@ -0,0 +1,41 @@
+// RUN: %clangxx_asan -O %s -o %t
+// RUN: not %run %t crash 2>&1 | FileCheck --check-prefix=CHECK-CRASH %s
+// RUN: not %run %t bad-bounds 2>&1 | FileCheck --check-prefix=CHECK-BAD %s
+// RUN: env ASAN_OPTIONS=detect_container_overflow=0 %run %t crash
+//
+// Test crash due to __sanitizer_annotate_contiguous_container.
+
+#include <assert.h>
+#include <string.h>
+
+extern "C" {
+void __sanitizer_annotate_contiguous_container(const void *beg, const void *end,
+ const void *old_mid,
+ const void *new_mid);
+} // extern "C"
+
+static volatile int one = 1;
+
+int TestCrash() {
+ long t[100];
+ t[60] = 0;
+ __sanitizer_annotate_contiguous_container(&t[0], &t[0] + 100, &t[0] + 100,
+ &t[0] + 50);
+ return (int)t[60 * one]; // Touches the poisoned memory.
+}
+
+void BadBounds() {
+ long t[100];
+ __sanitizer_annotate_contiguous_container(&t[0], &t[0] + 100, &t[0] + 101,
+ &t[0] + 50);
+}
+
+int main(int argc, char **argv) {
+ assert(argc == 2);
+ if (!strcmp(argv[1], "crash"))
+ return TestCrash();
+ else if (!strcmp(argv[1], "bad-bounds"))
+ BadBounds();
+}
+// CHECK-CRASH: AddressSanitizer: container-overflow
+// CHECK-BAD: ERROR: AddressSanitizer: bad parameters to __sanitizer_annotate_contiguous_container
diff --git a/test/asan/TestCases/current_allocated_bytes.cc b/test/asan/TestCases/current_allocated_bytes.cc
new file mode 100644
index 000000000000..c49e433b1e8b
--- /dev/null
+++ b/test/asan/TestCases/current_allocated_bytes.cc
@@ -0,0 +1,44 @@
+// RUN: %clangxx_asan -O0 %s -pthread -o %t && %run %t
+// RUN: %clangxx_asan -O2 %s -pthread -o %t && %run %t
+// REQUIRES: stable-runtime
+
+#include <assert.h>
+#include <pthread.h>
+#include <sanitizer/allocator_interface.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+const size_t kLargeAlloc = 1UL << 20;
+
+void* allocate(void *arg) {
+ volatile void *ptr = malloc(kLargeAlloc);
+ free((void*)ptr);
+ return 0;
+}
+
+void* check_stats(void *arg) {
+ assert(__sanitizer_get_current_allocated_bytes() > 0);
+ return 0;
+}
+
+int main() {
+ size_t used_mem = __sanitizer_get_current_allocated_bytes();
+ printf("Before: %zu\n", used_mem);
+ const int kNumIterations = 1000;
+ for (int iter = 0; iter < kNumIterations; iter++) {
+ pthread_t thr[4];
+ for (int j = 0; j < 4; j++) {
+ assert(0 ==
+ pthread_create(&thr[j], 0, (j < 2) ? allocate : check_stats, 0));
+ }
+ for (int j = 0; j < 4; j++)
+ assert(0 == pthread_join(thr[j], 0));
+ used_mem = __sanitizer_get_current_allocated_bytes();
+ if (used_mem > kLargeAlloc) {
+ printf("After iteration %d: %zu\n", iter, used_mem);
+ return 1;
+ }
+ }
+ printf("Success after %d iterations\n", kNumIterations);
+ return 0;
+}
diff --git a/test/asan/TestCases/debug_locate.cc b/test/asan/TestCases/debug_locate.cc
new file mode 100644
index 000000000000..5971a772786b
--- /dev/null
+++ b/test/asan/TestCases/debug_locate.cc
@@ -0,0 +1,80 @@
+// Checks the ASan memory address type debugging API, makes sure it returns
+// the correct memory type for heap, stack, global and shadow addresses and
+// that it correctly finds out which region (and name and size) the address
+// belongs to.
+// RUN: %clangxx_asan -O0 %s -o %t && %run %t 2>&1
+
+#include <assert.h>
+#include <sanitizer/asan_interface.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int global_var;
+
+int main() {
+ int local_var;
+ char *heap_ptr = (char *)malloc(10);
+
+ char name[100];
+ void *region_address;
+ size_t region_size;
+ const char *type;
+
+ type = __asan_locate_address(&global_var, name, 100,
+ &region_address, &region_size);
+ assert(0 == strcmp(name, "global_var"));
+ assert(0 == strcmp(type, "global"));
+ assert(region_address == &global_var);
+ assert(region_size == sizeof(global_var));
+
+ type = __asan_locate_address((char *)(&global_var)+1, name, 100,
+ &region_address, &region_size);
+ assert(0 == strcmp(name, "global_var"));
+ assert(0 == strcmp(type, "global"));
+ assert(region_address == &global_var);
+ assert(region_size == sizeof(global_var));
+
+ type = __asan_locate_address(&local_var, name, 100,
+ &region_address, &region_size);
+ assert(0 == strcmp(name, "local_var"));
+ assert(0 == strcmp(type, "stack"));
+ assert(region_address == &local_var);
+ assert(region_size == sizeof(local_var));
+
+ type = __asan_locate_address((char *)(&local_var)+1, name, 100,
+ &region_address, &region_size);
+ assert(0 == strcmp(name, "local_var"));
+ assert(0 == strcmp(type, "stack"));
+ assert(region_address == &local_var);
+ assert(region_size == sizeof(local_var));
+
+ type = __asan_locate_address(heap_ptr, name, 100,
+ &region_address, &region_size);
+ assert(0 == strcmp(type, "heap"));
+ assert(region_address == heap_ptr);
+ assert(10 == region_size);
+
+ type = __asan_locate_address(heap_ptr+1, name, 100,
+ &region_address, &region_size);
+ assert(0 == strcmp(type, "heap"));
+ assert(region_address == heap_ptr);
+ assert(10 == region_size);
+
+ size_t shadow_scale;
+ size_t shadow_offset;
+ __asan_get_shadow_mapping(&shadow_scale, &shadow_offset);
+
+ uintptr_t shadow_ptr = (((uintptr_t)heap_ptr) >> shadow_scale)
+ + shadow_offset;
+ type = __asan_locate_address((void *)shadow_ptr, NULL, 0, NULL, NULL);
+ assert((0 == strcmp(type, "high shadow")) || 0 == strcmp(type, "low shadow"));
+
+ uintptr_t shadow_gap = (shadow_ptr >> shadow_scale) + shadow_offset;
+ type = __asan_locate_address((void *)shadow_gap, NULL, 0, NULL, NULL);
+ assert(0 == strcmp(type, "shadow gap"));
+
+ free(heap_ptr);
+
+ return 0;
+}
diff --git a/test/asan/TestCases/debug_mapping.cc b/test/asan/TestCases/debug_mapping.cc
new file mode 100644
index 000000000000..f96abf6d11cf
--- /dev/null
+++ b/test/asan/TestCases/debug_mapping.cc
@@ -0,0 +1,24 @@
+// Checks that the debugging API returns correct shadow scale and offset.
+// RUN: %clangxx_asan -O %s -o %t
+// RUN: env ASAN_OPTIONS=verbosity=1 %run %t 2>&1 | FileCheck %s
+
+#include <sanitizer/asan_interface.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+// printed because of verbosity=1
+// CHECK: SHADOW_SCALE: [[SCALE:[0-9]+]]
+// CHECK: SHADOW_OFFSET: [[OFFSET:[0-9]+]]
+
+int main() {
+ size_t scale, offset;
+ __asan_get_shadow_mapping(&scale, &offset);
+
+ fprintf(stderr, "scale: %lx\n", scale);
+ fprintf(stderr, "offset: %lx\n", offset);
+
+ // CHECK: scale: [[SCALE]]
+ // CHECK: offset: [[OFFSET]]
+
+ return 0;
+}
diff --git a/test/asan/TestCases/debug_ppc64_mapping.cc b/test/asan/TestCases/debug_ppc64_mapping.cc
new file mode 100644
index 000000000000..3ddd3e1404ce
--- /dev/null
+++ b/test/asan/TestCases/debug_ppc64_mapping.cc
@@ -0,0 +1,37 @@
+// RUN: %clang_asan -O0 %s -o %t
+// RUN: env ASAN_OPTIONS=verbosity=0 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-PPC64-V0
+// RUN: env ASAN_OPTIONS=verbosity=2 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-PPC64
+// REQUIRES: powerpc64-supported-target
+
+#include <stdio.h>
+
+int main() {
+// CHECK-PPC64: || `[{{0x0a0|0x040}}000000000, {{0x3ff|0x0ff}}fffffffff]` || HighMem ||
+// CHECK-PPC64: || `[{{0x034|0x028}}000000000, {{0x09f|0x03f}}fffffffff]` || HighShadow ||
+// CHECK-PPC64: || `[{{0x024|0x024}}000000000, {{0x033|0x027}}fffffffff]` || ShadowGap ||
+// CHECK-PPC64: || `[0x020000000000, 0x023fffffffff]` || LowShadow ||
+// CHECK-PPC64: || `[0x000000000000, 0x01ffffffffff]` || LowMem ||
+//
+ printf("ppc64 eyecatcher \n");
+// CHECK-PPC64-V0: ppc64 eyecatcher
+
+ return 0;
+}
+
+/*
+ * Two different signatures noted at the time of writing.
+Newish kernel: (64TB address range support, starting with kernel version 3.7)
+|| `[0x0a0000000000, 0x3fffffffffff]` || HighMem ||
+|| `[0x034000000000, 0x09ffffffffff]` || HighShadow ||
+|| `[0x024000000000, 0x033fffffffff]` || ShadowGap ||
+|| `[0x020000000000, 0x023fffffffff]` || LowShadow ||
+|| `[0x000000000000, 0x01ffffffffff]` || LowMem ||
+
+Oldish kernel:
+|| `[0x040000000000, 0x0fffffffffff]` || HighMem ||
+|| `[0x028000000000, 0x03ffffffffff]` || HighShadow ||
+|| `[0x024000000000, 0x027fffffffff]` || ShadowGap ||
+|| `[0x020000000000, 0x023fffffffff]` || LowShadow ||
+|| `[0x000000000000, 0x01ffffffffff]` || LowMem ||
+*/
+
diff --git a/test/asan/TestCases/debug_report.cc b/test/asan/TestCases/debug_report.cc
new file mode 100644
index 000000000000..acf52f918dd8
--- /dev/null
+++ b/test/asan/TestCases/debug_report.cc
@@ -0,0 +1,48 @@
+// Checks that the ASan debugging API for getting report information
+// returns correct values.
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+#include <sanitizer/asan_interface.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+ char *heap_ptr = (char *)malloc(10);
+ free(heap_ptr);
+ int present = __asan_report_present();
+ fprintf(stderr, "%s\n", (present == 0) ? "no report" : "");
+ // CHECK: no report
+ heap_ptr[0] = 'A'; // BOOM
+ return 0;
+}
+
+void __asan_on_error() {
+ int present = __asan_report_present();
+ void *pc = __asan_get_report_pc();
+ void *bp = __asan_get_report_bp();
+ void *sp = __asan_get_report_sp();
+ void *addr = __asan_get_report_address();
+ int is_write = __asan_get_report_access_type();
+ size_t access_size = __asan_get_report_access_size();
+ const char *description = __asan_get_report_description();
+
+ fprintf(stderr, "%s\n", (present == 1) ? "report" : "");
+ // CHECK: report
+ fprintf(stderr, "pc: %p\n", pc);
+ // CHECK: pc: 0x[[PC:[0-9a-f]+]]
+ fprintf(stderr, "bp: %p\n", bp);
+ // CHECK: bp: 0x[[BP:[0-9a-f]+]]
+ fprintf(stderr, "sp: %p\n", sp);
+ // CHECK: sp: 0x[[SP:[0-9a-f]+]]
+ fprintf(stderr, "addr: %p\n", addr);
+ // CHECK: addr: 0x[[ADDR:[0-9a-f]+]]
+ fprintf(stderr, "type: %s\n", (is_write ? "write" : "read"));
+ // CHECK: type: write
+ fprintf(stderr, "access_size: %ld\n", access_size);
+ // CHECK: access_size: 1
+ fprintf(stderr, "description: %s\n", description);
+ // CHECK: description: heap-use-after-free
+}
+
+// CHECK: AddressSanitizer: heap-use-after-free on address {{0x0*}}[[ADDR]] at pc {{0x0*}}[[PC]] bp {{0x0*}}[[BP]] sp {{0x0*}}[[SP]]
+// CHECK: WRITE of size 1 at {{0x0*}}[[ADDR]] thread T0
diff --git a/test/asan/TestCases/debug_stacks.cc b/test/asan/TestCases/debug_stacks.cc
new file mode 100644
index 000000000000..57bb5465035a
--- /dev/null
+++ b/test/asan/TestCases/debug_stacks.cc
@@ -0,0 +1,62 @@
+// Check that the stack trace debugging API works and returns correct
+// malloc and free stacks.
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+#include <sanitizer/asan_interface.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+char *mem;
+void func1() {
+ mem = (char *)malloc(10);
+}
+
+void func2() {
+ free(mem);
+}
+
+int main() {
+ func1();
+ func2();
+
+ void *trace[100];
+ size_t num_frames = 100;
+ int thread_id;
+ num_frames = __asan_get_alloc_stack(mem, trace, num_frames, &thread_id);
+
+ fprintf(stderr, "alloc stack retval %s\n", (num_frames > 0 && num_frames < 10)
+ ? "ok" : "");
+ // CHECK: alloc stack retval ok
+ fprintf(stderr, "thread id = %d\n", thread_id);
+ // CHECK: thread id = 0
+ fprintf(stderr, "0x%lx\n", trace[0]);
+ // CHECK: [[ALLOC_FRAME_0:0x[0-9a-f]+]]
+ fprintf(stderr, "0x%lx\n", trace[1]);
+ // CHECK: [[ALLOC_FRAME_1:0x[0-9a-f]+]]
+
+ num_frames = 100;
+ num_frames = __asan_get_free_stack(mem, trace, num_frames, &thread_id);
+
+ fprintf(stderr, "free stack retval %s\n", (num_frames > 0 && num_frames < 10)
+ ? "ok" : "");
+ // CHECK: free stack retval ok
+ fprintf(stderr, "thread id = %d\n", thread_id);
+ // CHECK: thread id = 0
+ fprintf(stderr, "0x%lx\n", trace[0]);
+ // CHECK: [[FREE_FRAME_0:0x[0-9a-f]+]]
+ fprintf(stderr, "0x%lx\n", trace[1]);
+ // CHECK: [[FREE_FRAME_1:0x[0-9a-f]+]]
+
+ mem[0] = 'A'; // BOOM
+
+ // CHECK: ERROR: AddressSanitizer: heap-use-after-free
+ // CHECK: WRITE of size 1 at 0x{{.*}}
+ // CHECK: freed by thread T0 here:
+ // CHECK: #0 [[FREE_FRAME_0]]
+ // CHECK: #1 [[FREE_FRAME_1]]
+ // CHECK: previously allocated by thread T0 here:
+ // CHECK: #0 [[ALLOC_FRAME_0]]
+ // CHECK: #1 [[ALLOC_FRAME_1]]
+
+ return 0;
+}
diff --git a/test/asan/TestCases/deep_call_stack.cc b/test/asan/TestCases/deep_call_stack.cc
new file mode 100644
index 000000000000..789f23454d19
--- /dev/null
+++ b/test/asan/TestCases/deep_call_stack.cc
@@ -0,0 +1,25 @@
+// Check that UAR mode can handle very deep recusrion.
+// export ASAN_OPTIONS=detect_stack_use_after_return=1
+// RUN: %clangxx_asan -O2 %s -o %t && \
+// RUN: (ulimit -s 4096; %run %t) 2>&1 | FileCheck %s
+// Also check that use_sigaltstack+verbosity doesn't crash.
+// RUN: env ASAN_OPTIONS=verbosity=1:use_sigaltstack=1 %run %t | FileCheck %s
+#include <stdio.h>
+
+__attribute__((noinline))
+void RecursiveFunc(int depth, int *ptr) {
+ if ((depth % 1000) == 0)
+ printf("[%05d] ptr: %p\n", depth, ptr);
+ if (depth == 0)
+ return;
+ int local;
+ RecursiveFunc(depth - 1, &local);
+}
+
+int main(int argc, char **argv) {
+ RecursiveFunc(15000, 0);
+ return 0;
+}
+// CHECK: [15000] ptr:
+// CHECK: [07000] ptr:
+// CHECK: [00000] ptr:
diff --git a/test/asan/TestCases/deep_stack_uaf.cc b/test/asan/TestCases/deep_stack_uaf.cc
new file mode 100644
index 000000000000..3e88d697fcef
--- /dev/null
+++ b/test/asan/TestCases/deep_stack_uaf.cc
@@ -0,0 +1,36 @@
+// Check that we can store lots of stack frames if asked to.
+
+// RUN: %clangxx_asan -O0 %s -o %t 2>&1
+// RUN: env ASAN_OPTIONS=malloc_context_size=120:redzone=512 not %run %t 2>&1 | FileCheck %s
+// XFAIL: arm-linux-gnueabi
+// XFAIL: armv7l-unknown-linux-gnueabihf
+#include <stdlib.h>
+#include <stdio.h>
+
+template <int depth>
+struct DeepFree {
+ static void free(char *x) {
+ DeepFree<depth - 1>::free(x);
+ }
+};
+
+template<>
+struct DeepFree<0> {
+ static void free(char *x) {
+ ::free(x);
+ }
+};
+
+int main() {
+ char *x = (char*)malloc(10);
+ // deep_free(x);
+ DeepFree<200>::free(x);
+ return x[5];
+ // CHECK: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}}
+ // The libcxxrt demangling procedure on FreeBSD 9.2 incorrectly appends
+ // extra 'E' characters to the end of template arguments; see:
+ // https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=192115
+ // CHECK: {{DeepFree<36>|DeepFree<36E>}}
+ // CHECK: {{DeepFree<98>|DeepFree<98E>}}
+ // CHECK: {{DeepFree<115>|DeepFree<115E>}}
+}
diff --git a/test/asan/TestCases/deep_tail_call.cc b/test/asan/TestCases/deep_tail_call.cc
new file mode 100644
index 000000000000..628ef06db144
--- /dev/null
+++ b/test/asan/TestCases/deep_tail_call.cc
@@ -0,0 +1,20 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// 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
+
+// CHECK: AddressSanitizer: global-buffer-overflow
+int global[10];
+// CHECK: {{#0.*call4}}
+void __attribute__((noinline)) call4(int i) { global[i+10]++; }
+// CHECK: {{#1.*call3}}
+void __attribute__((noinline)) call3(int i) { call4(i); }
+// CHECK: {{#2.*call2}}
+void __attribute__((noinline)) call2(int i) { call3(i); }
+// CHECK: {{#3.*call1}}
+void __attribute__((noinline)) call1(int i) { call2(i); }
+// CHECK: {{#4.*main}}
+int main(int argc, char **argv) {
+ call1(argc);
+ return global[0];
+}
diff --git a/test/asan/TestCases/deep_thread_stack.cc b/test/asan/TestCases/deep_thread_stack.cc
new file mode 100644
index 000000000000..535da79ff58d
--- /dev/null
+++ b/test/asan/TestCases/deep_thread_stack.cc
@@ -0,0 +1,58 @@
+// RUN: %clangxx_asan -O0 %s -pthread -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -pthread -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -pthread -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -pthread -o %t && not %run %t 2>&1 | FileCheck %s
+// REQUIRES: stable-runtime
+
+#include <pthread.h>
+
+int *x;
+
+void *AllocThread(void *arg) {
+ x = new int;
+ *x = 42;
+ return NULL;
+}
+
+void *FreeThread(void *arg) {
+ delete x;
+ return NULL;
+}
+
+void *AccessThread(void *arg) {
+ *x = 43; // BOOM
+ return NULL;
+}
+
+typedef void* (*callback_type)(void* arg);
+
+void *RunnerThread(void *function) {
+ pthread_t thread;
+ pthread_create(&thread, NULL, (callback_type)function, NULL);
+ pthread_join(thread, NULL);
+ return NULL;
+}
+
+void RunThread(callback_type function) {
+ pthread_t runner;
+ pthread_create(&runner, NULL, RunnerThread, (void*)function);
+ pthread_join(runner, NULL);
+}
+
+int main(int argc, char *argv[]) {
+ RunThread(AllocThread);
+ RunThread(FreeThread);
+ RunThread(AccessThread);
+ return (x != 0);
+}
+
+// CHECK: AddressSanitizer: heap-use-after-free
+// CHECK: WRITE of size 4 at 0x{{.*}} thread T[[ACCESS_THREAD:[0-9]+]]
+// CHECK: freed by thread T[[FREE_THREAD:[0-9]+]] here:
+// CHECK: previously allocated by thread T[[ALLOC_THREAD:[0-9]+]] here:
+// CHECK: Thread T[[ACCESS_THREAD]] created by T[[ACCESS_RUNNER:[0-9]+]] here:
+// CHECK: Thread T[[ACCESS_RUNNER]] created by T0 here:
+// CHECK: Thread T[[FREE_THREAD]] created by T[[FREE_RUNNER:[0-9]+]] here:
+// CHECK: Thread T[[FREE_RUNNER]] created by T0 here:
+// CHECK: Thread T[[ALLOC_THREAD]] created by T[[ALLOC_RUNNER:[0-9]+]] here:
+// CHECK: Thread T[[ALLOC_RUNNER]] created by T0 here:
diff --git a/test/asan/TestCases/default_blacklist.cc b/test/asan/TestCases/default_blacklist.cc
new file mode 100644
index 000000000000..9358cc47cbaa
--- /dev/null
+++ b/test/asan/TestCases/default_blacklist.cc
@@ -0,0 +1,6 @@
+// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316
+// XFAIL: android
+//
+// Test that ASan uses the default blacklist from resource directory.
+// RUN: %clangxx_asan -### %s 2>&1 | FileCheck %s
+// CHECK: fsanitize-blacklist={{.*}}asan_blacklist.txt
diff --git a/test/asan/TestCases/default_options.cc b/test/asan/TestCases/default_options.cc
new file mode 100644
index 000000000000..6453f66a9523
--- /dev/null
+++ b/test/asan/TestCases/default_options.cc
@@ -0,0 +1,18 @@
+// RUN: %clangxx_asan -O2 %s -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+
+// __asan_default_options() are not supported on Windows.
+// XFAIL: win32
+
+const char *kAsanDefaultOptions="verbosity=1 foo=bar";
+
+extern "C"
+__attribute__((no_sanitize_address))
+const char *__asan_default_options() {
+ // CHECK: Using the defaults from __asan_default_options: {{.*}} foo=bar
+ return kAsanDefaultOptions;
+}
+
+int main() {
+ return 0;
+}
diff --git a/test/asan/TestCases/describe_address.cc b/test/asan/TestCases/describe_address.cc
new file mode 100644
index 000000000000..868c0eb1c446
--- /dev/null
+++ b/test/asan/TestCases/describe_address.cc
@@ -0,0 +1,19 @@
+// RUN: %clangxx_asan -O0 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <sanitizer/asan_interface.h>
+
+int global;
+
+int main(int argc, char *argv[]) {
+ int stack;
+ int *heap = new int[100];
+ __asan_describe_address(heap);
+ // CHECK: {{.*}} is located 0 bytes inside of 400-byte region
+ // CHECK: allocated by thread T{{.*}} here
+ __asan_describe_address(&stack);
+ // CHECK: Address {{.*}} is located in stack of thread T{{.*}} at offset {{.*}}
+ __asan_describe_address(&global);
+ // CHECK: {{.*}} is located 0 bytes inside of global variable 'global'
+ delete[] heap;
+ return 0;
+}
diff --git a/test/asan/TestCases/dlclose-test.cc b/test/asan/TestCases/dlclose-test.cc
new file mode 100644
index 000000000000..094453f3de2a
--- /dev/null
+++ b/test/asan/TestCases/dlclose-test.cc
@@ -0,0 +1,99 @@
+// Regression test for
+// http://code.google.com/p/address-sanitizer/issues/detail?id=19
+// Bug description:
+// 1. application dlopens foo.so
+// 2. asan registers all globals from foo.so
+// 3. application dlcloses foo.so
+// 4. application mmaps some memory to the location where foo.so was before
+// 5. application starts using this mmaped memory, but asan still thinks there
+// are globals.
+// 6. BOOM
+
+// This sublte test assumes that after a foo.so is dlclose-d
+// we can mmap the region of memory that has been occupied by the library.
+// It works on i368/x86_64 Linux, but not necessary anywhere else.
+// REQUIRES: x86_64-supported-target,i386-supported-target
+
+// RUN: %clangxx_asan -O0 -DSHARED_LIB %s -fPIC -shared -o %t-so.so
+// RUN: %clangxx_asan -O0 %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 -DSHARED_LIB %s -fPIC -shared -o %t-so.so
+// RUN: %clangxx_asan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 -DSHARED_LIB %s -fPIC -shared -o %t-so.so
+// RUN: %clangxx_asan -O2 %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 -DSHARED_LIB %s -fPIC -shared -o %t-so.so
+// RUN: %clangxx_asan -O3 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#if !defined(SHARED_LIB)
+#include <assert.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <string>
+
+using std::string;
+
+typedef int *(fun_t)();
+
+int main(int argc, char *argv[]) {
+ string path = string(argv[0]) + "-so.so";
+ size_t PageSize = sysconf(_SC_PAGESIZE);
+ printf("opening %s ... \n", path.c_str());
+ void *lib = dlopen(path.c_str(), RTLD_NOW);
+ if (!lib) {
+ printf("error in dlopen(): %s\n", dlerror());
+ return 1;
+ }
+ fun_t *get = (fun_t*)dlsym(lib, "get_address_of_static_var");
+ if (!get) {
+ printf("failed dlsym\n");
+ return 1;
+ }
+ int *addr = get();
+ assert(((size_t)addr % 32) == 0); // should be 32-byte aligned.
+ printf("addr: %p\n", addr);
+ addr[0] = 1; // make sure we can write there.
+
+ // Now dlclose the shared library.
+ printf("attempting to dlclose\n");
+ if (dlclose(lib)) {
+ printf("failed to dlclose\n");
+ return 1;
+ }
+ // Now, the page where 'addr' is unmapped. Map it.
+ size_t page_beg = ((size_t)addr) & ~(PageSize - 1);
+ void *res = mmap((void*)(page_beg), PageSize,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, -1, 0);
+ if (res == (char*)-1L) {
+ printf("failed to mmap\n");
+ return 1;
+ }
+ addr[1] = 2; // BOOM (if the bug is not fixed).
+ printf("PASS\n");
+ // CHECK: PASS
+ return 0;
+}
+#else // SHARED_LIB
+#include <stdio.h>
+
+static int pad1;
+static int static_var;
+static int pad2;
+
+extern "C"
+int *get_address_of_static_var() {
+ return &static_var;
+}
+
+__attribute__((constructor))
+void at_dlopen() {
+ printf("%s: I am being dlopened\n", __FILE__);
+}
+__attribute__((destructor))
+void at_dlclose() {
+ printf("%s: I am being dlclosed\n", __FILE__);
+}
+#endif // SHARED_LIB
diff --git a/test/asan/TestCases/double-free.cc b/test/asan/TestCases/double-free.cc
new file mode 100644
index 000000000000..f0dd29174849
--- /dev/null
+++ b/test/asan/TestCases/double-free.cc
@@ -0,0 +1,27 @@
+// RUN: %clangxx_asan -O0 %s -o %t 2>&1
+// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=MALLOC-CTX
+
+// Also works if no malloc context is available.
+// RUN: env ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=0 not %run %t 2>&1 | FileCheck %s
+// RUN: env ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=1 not %run %t 2>&1 | FileCheck %s
+// XFAIL: arm-linux-gnueabi
+// XFAIL: armv7l-unknown-linux-gnueabihf
+
+#include <stdlib.h>
+#include <string.h>
+int main(int argc, char **argv) {
+ char *x = (char*)malloc(10 * sizeof(char));
+ memset(x, 0, 10);
+ int res = x[argc];
+ free(x);
+ free(x + argc - 1); // BOOM
+ // CHECK: AddressSanitizer: attempting double-free{{.*}}in thread T0
+ // CHECK: #0 0x{{.*}} in {{.*}}free
+ // CHECK: #1 0x{{.*}} in main {{.*}}double-free.cc:[[@LINE-3]]
+ // CHECK: freed by thread T0 here:
+ // MALLOC-CTX: #0 0x{{.*}} in {{.*}}free
+ // MALLOC-CTX: #1 0x{{.*}} in main {{.*}}double-free.cc:[[@LINE-7]]
+ // CHECK: allocated by thread T0 here:
+ // MALLOC-CTX: double-free.cc:[[@LINE-12]]
+ return res;
+}
diff --git a/test/asan/TestCases/dump_instruction_bytes.cc b/test/asan/TestCases/dump_instruction_bytes.cc
new file mode 100644
index 000000000000..981e3c31327f
--- /dev/null
+++ b/test/asan/TestCases/dump_instruction_bytes.cc
@@ -0,0 +1,20 @@
+// Check that ASan prints the faulting instruction bytes on
+// dump_instruction_bytes=1
+// RUN: %clangxx_asan %s -o %t
+// RUN: env ASAN_OPTIONS=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
+
+int main() {
+#if defined(__x86_64__)
+ asm("movq $0, %rax");
+ asm("movl $0xcafebabe, 0x0(%rax)");
+#elif defined(i386)
+ asm("movl $0, %eax");
+ asm("movl $0xcafebabe, 0x0(%eax)");
+#endif
+ // CHECK-DUMP: First 16 instruction bytes at pc: c7 00 be ba fe ca
+ // CHECK-NODUMP-NOT: First 16 instruction bytes
+ return 0;
+}
diff --git a/test/asan/TestCases/force_inline_opt0.cc b/test/asan/TestCases/force_inline_opt0.cc
new file mode 100644
index 000000000000..e6e5d26c7998
--- /dev/null
+++ b/test/asan/TestCases/force_inline_opt0.cc
@@ -0,0 +1,14 @@
+// This test checks that we are no instrumenting a memory access twice
+// (before and after inlining)
+// RUN: %clangxx_asan -O1 %s -o %t && %run %t
+// RUN: %clangxx_asan -O0 %s -o %t && %run %t
+__attribute__((always_inline))
+void foo(int *x) {
+ *x = 0;
+}
+
+int main() {
+ int x;
+ foo(&x);
+ return x;
+}
diff --git a/test/asan/TestCases/free_hook_realloc.cc b/test/asan/TestCases/free_hook_realloc.cc
new file mode 100644
index 000000000000..4b2753252a8d
--- /dev/null
+++ b/test/asan/TestCases/free_hook_realloc.cc
@@ -0,0 +1,37 @@
+// Check that free hook doesn't conflict with Realloc.
+// RUN: %clangxx_asan -O2 %s -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+
+// Malloc/free hooks are not supported on Windows.
+// XFAIL: win32
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sanitizer/allocator_interface.h>
+
+static void *glob_ptr;
+
+extern "C" {
+void __sanitizer_free_hook(const volatile void *ptr) {
+ if (ptr == glob_ptr) {
+ *(int*)ptr = 0;
+ write(1, "FreeHook\n", sizeof("FreeHook\n"));
+ }
+}
+}
+
+int main() {
+ int *x = (int*)malloc(100);
+ x[0] = 42;
+ glob_ptr = x;
+ int *y = (int*)realloc(x, 200);
+ // Verify that free hook was called and didn't spoil the memory.
+ if (y[0] != 42) {
+ _exit(1);
+ }
+ write(1, "Passed\n", sizeof("Passed\n"));
+ free(y);
+ // CHECK: FreeHook
+ // CHECK: Passed
+ return 0;
+}
diff --git a/test/asan/TestCases/frexp_interceptor.cc b/test/asan/TestCases/frexp_interceptor.cc
new file mode 100644
index 000000000000..d75ba992b650
--- /dev/null
+++ b/test/asan/TestCases/frexp_interceptor.cc
@@ -0,0 +1,16 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+// Test the frexp() interceptor.
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+int main() {
+ double x = 3.14;
+ int *exp = (int*)malloc(sizeof(int));
+ free(exp);
+ double y = frexp(x, exp);
+ // CHECK: use-after-free
+ // CHECK: SUMMARY
+ return 0;
+}
diff --git a/test/asan/TestCases/gc-test.cc b/test/asan/TestCases/gc-test.cc
new file mode 100644
index 000000000000..ffbea85b2650
--- /dev/null
+++ b/test/asan/TestCases/gc-test.cc
@@ -0,0 +1,50 @@
+// RUN: %clangxx_asan %s -pthread -o %t
+// RUN: env ASAN_OPTIONS=detect_stack_use_after_return=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1
+// RUN: env ASAN_OPTIONS=detect_stack_use_after_return=0 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0
+// REQUIRES: stable-runtime
+
+#include <assert.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <sanitizer/asan_interface.h>
+
+static const int kNumThreads = 2;
+
+void *Thread(void *unused) {
+ void *fake_stack = __asan_get_current_fake_stack();
+ char var[15];
+ if (fake_stack) {
+ fprintf(stderr, "fake stack found: %p; var: %p\n", fake_stack, var);
+ // CHECK1: fake stack found
+ // CHECK1: fake stack found
+ void *beg, *end;
+ void *real_stack =
+ __asan_addr_is_in_fake_stack(fake_stack, &var[0], &beg, &end);
+ assert(real_stack);
+ assert((char*)beg <= (char*)&var[0]);
+ assert((char*)end > (char*)&var[0]);
+ for (int i = -32; i < 15; i++) {
+ void *beg1, *end1;
+ char *ptr = &var[0] + i;
+ void *real_stack1 =
+ __asan_addr_is_in_fake_stack(fake_stack, ptr, &beg1, &end1);
+ assert(real_stack == real_stack1);
+ assert(beg == beg1);
+ assert(end == end1);
+ }
+ } else {
+ fprintf(stderr, "no fake stack\n");
+ // CHECK0: no fake stack
+ // CHECK0: no fake stack
+ }
+ return NULL;
+}
+
+int main(int argc, char **argv) {
+ pthread_t t[kNumThreads];
+ for (int i = 0; i < kNumThreads; i++)
+ pthread_create(&t[i], 0, Thread, 0);
+ for (int i = 0; i < kNumThreads; i++)
+ pthread_join(t[i], 0);
+ return 0;
+}
diff --git a/test/asan/TestCases/global-demangle.cc b/test/asan/TestCases/global-demangle.cc
new file mode 100644
index 000000000000..5f7ff91b1601
--- /dev/null
+++ b/test/asan/TestCases/global-demangle.cc
@@ -0,0 +1,17 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+namespace XXX {
+class YYY {
+ public:
+ static char ZZZ[];
+};
+char YYY::ZZZ[] = "abc";
+}
+
+int main(int argc, char **argv) {
+ return (int)XXX::YYY::ZZZ[argc + 5]; // BOOM
+ // CHECK: {{READ of size 1 at 0x.*}}
+ // CHECK: {{0x.* is located 2 bytes to the right of global variable}}
+ // CHECK: 'XXX::YYY::ZZZ' {{.*}} of size 4
+ // CHECK: 'XXX::YYY::ZZZ' is ascii string 'abc'
+}
diff --git a/test/asan/TestCases/global-location.cc b/test/asan/TestCases/global-location.cc
new file mode 100644
index 000000000000..795e50bf614e
--- /dev/null
+++ b/test/asan/TestCases/global-location.cc
@@ -0,0 +1,38 @@
+// RUN: %clangxx_asan -O2 %s -o %t
+// RUN: not %run %t g 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=GLOB
+// RUN: not %run %t c 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CLASS_STATIC
+// RUN: not %run %t f 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=FUNC_STATIC
+// RUN: not %run %t l 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=LITERAL
+
+// CHECK: AddressSanitizer: global-buffer-overflow
+
+#include <string.h>
+
+struct C {
+ static int array[10];
+};
+
+int global[10];
+// GLOB: 0x{{.*}} is located 4 bytes to the right of global variable 'global' defined in '{{.*}}global-location.cc:[[@LINE-1]]:5' {{.*}} of size 40
+int C::array[10];
+// CLASS_STATIC: 0x{{.*}} is located 4 bytes to the right of global variable 'C::array' defined in '{{.*}}global-location.cc:[[@LINE-1]]:8' {{.*}} of size 40
+
+int main(int argc, char **argv) {
+ int one = argc - 1;
+ switch (argv[1][0]) {
+ case 'g': return global[one * 11];
+ case 'c': return C::array[one * 11];
+ case 'f':
+ static int array[10];
+ // FUNC_STATIC: 0x{{.*}} is located 4 bytes to the right of global variable 'array' defined in '{{.*}}global-location.cc:[[@LINE-1]]:16' {{.*}} of size 40
+ memset(array, 0, 10);
+ return array[one * 11];
+ case 'l':
+ const char *str = "0123456789";
+ // LITERAL: 0x{{.*}} is located 0 bytes to the right of global variable {{.*}} defined in '{{.*}}global-location.cc:[[@LINE-1]]:23' {{.*}} of size 11
+ return str[one * 11];
+ }
+ return 0;
+}
+
+// CHECK: SUMMARY: AddressSanitizer: global-buffer-overflow
diff --git a/test/asan/TestCases/global-overflow.cc b/test/asan/TestCases/global-overflow.cc
new file mode 100644
index 000000000000..a39a95306352
--- /dev/null
+++ b/test/asan/TestCases/global-overflow.cc
@@ -0,0 +1,21 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// 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
+
+#include <string.h>
+int main(int argc, char **argv) {
+ static char XXX[10];
+ static char YYY[10];
+ static char ZZZ[10];
+ memset(XXX, 0, 10);
+ memset(YYY, 0, 10);
+ memset(ZZZ, 0, 10);
+ int res = YYY[argc * 10]; // BOOOM
+ // CHECK: {{READ of size 1 at 0x.* thread T0}}
+ // CHECK: {{ #0 0x.* in main .*global-overflow.cc:}}[[@LINE-2]]
+ // CHECK: {{0x.* is located 0 bytes to the right of global variable}}
+ // CHECK: {{.*YYY.* of size 10}}
+ res += XXX[argc] + ZZZ[argc];
+ return res;
+}
diff --git a/test/asan/TestCases/heap-overflow-large.cc b/test/asan/TestCases/heap-overflow-large.cc
new file mode 100644
index 000000000000..eb2fcc3220e7
--- /dev/null
+++ b/test/asan/TestCases/heap-overflow-large.cc
@@ -0,0 +1,23 @@
+// Regression test for
+// https://code.google.com/p/address-sanitizer/issues/detail?id=183
+
+// RUN: %clangxx_asan -O2 %s -o %t
+// RUN: not %run %t 12 2>&1 | FileCheck %s
+// RUN: not %run %t 100 2>&1 | FileCheck %s
+// RUN: not %run %t 10000 2>&1 | FileCheck %s
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+int main(int argc, char *argv[]) {
+ fprintf(stderr, "main\n");
+ int *x = new int[5];
+ memset(x, 0, sizeof(x[0]) * 5);
+ int index = atoi(argv[1]);
+ int res = x[index];
+ // CHECK: main
+ // CHECK-NOT: CHECK failed
+ delete[] x;
+ return res ? res : 1;
+}
diff --git a/test/asan/TestCases/heap-overflow.cc b/test/asan/TestCases/heap-overflow.cc
new file mode 100644
index 000000000000..70a1203562be
--- /dev/null
+++ b/test/asan/TestCases/heap-overflow.cc
@@ -0,0 +1,24 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// 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
+// RUN: env ASAN_OPTIONS=print_stats=1 not %run %t 2>&1 | FileCheck %s
+
+// FIXME: Fix this test under GCC.
+// REQUIRES: Clang
+
+#include <stdlib.h>
+#include <string.h>
+int main(int argc, char **argv) {
+ char *x = (char*)malloc(10 * sizeof(char));
+ memset(x, 0, 10);
+ int res = x[argc * 10]; // BOOOM
+ // CHECK: {{READ of size 1 at 0x.* thread T0}}
+ // CHECK: {{ #0 0x.* in main .*heap-overflow.cc:}}[[@LINE-2]]
+ // CHECK: {{0x.* is located 0 bytes to the right of 10-byte region}}
+ // CHECK: {{allocated by thread T0 here:}}
+
+ // CHECK: {{ #0 0x.* in .*malloc}}
+ free(x);
+ return res;
+}
diff --git a/test/asan/TestCases/heavy_uar_test.cc b/test/asan/TestCases/heavy_uar_test.cc
new file mode 100644
index 000000000000..1f8caea21690
--- /dev/null
+++ b/test/asan/TestCases/heavy_uar_test.cc
@@ -0,0 +1,60 @@
+// RUN: export ASAN_OPTIONS=detect_stack_use_after_return=1
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// XFAIL: arm-linux-gnueabi
+
+// FIXME: Fix this test under GCC.
+// REQUIRES: Clang
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+__attribute__((noinline))
+char *pretend_to_do_something(char *x) {
+ __asm__ __volatile__("" : : "r" (x) : "memory");
+ return x;
+}
+
+__attribute__((noinline))
+char *LeakStack() {
+ char x[1024];
+ memset(x, 0, sizeof(x));
+ return pretend_to_do_something(x);
+}
+
+template<size_t kFrameSize>
+__attribute__((noinline))
+void RecursiveFunctionWithStackFrame(int depth) {
+ if (depth <= 0) return;
+ char x[kFrameSize];
+ x[0] = depth;
+ pretend_to_do_something(x);
+ RecursiveFunctionWithStackFrame<kFrameSize>(depth - 1);
+}
+
+int main(int argc, char **argv) {
+ int n_iter = argc >= 2 ? atoi(argv[1]) : 1000;
+ int depth = argc >= 3 ? atoi(argv[2]) : 500;
+ for (int i = 0; i < n_iter; i++) {
+ RecursiveFunctionWithStackFrame<10>(depth);
+ RecursiveFunctionWithStackFrame<100>(depth);
+ RecursiveFunctionWithStackFrame<500>(depth);
+ RecursiveFunctionWithStackFrame<1024>(depth);
+ RecursiveFunctionWithStackFrame<2000>(depth);
+ // The stack size is tight for the main thread in multithread
+ // environment on FreeBSD.
+#if !defined(__FreeBSD__)
+ RecursiveFunctionWithStackFrame<5000>(depth);
+ RecursiveFunctionWithStackFrame<10000>(depth);
+#endif
+ }
+ char *stale_stack = LeakStack();
+ RecursiveFunctionWithStackFrame<1024>(10);
+ stale_stack[100]++;
+ // CHECK: ERROR: AddressSanitizer: stack-use-after-return on address
+ // CHECK: is located in stack of thread T0 at offset {{116|132}} in frame
+ // CHECK: in LeakStack{{.*}}heavy_uar_test.cc:
+ // CHECK: [{{16|32}}, {{1040|1056}}) 'x'
+ return 0;
+}
diff --git a/test/asan/TestCases/huge_negative_hea_oob.cc b/test/asan/TestCases/huge_negative_hea_oob.cc
new file mode 100644
index 000000000000..96e7e613d4bb
--- /dev/null
+++ b/test/asan/TestCases/huge_negative_hea_oob.cc
@@ -0,0 +1,13 @@
+// RUN: %clangxx_asan %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O %s -o %t && not %run %t 2>&1 | FileCheck %s
+// Check that we can find huge buffer overflows to the left.
+#include <stdlib.h>
+#include <string.h>
+int main(int argc, char **argv) {
+ char *x = (char*)malloc(1 << 20);
+ memset(x, 0, 10);
+ int res = x[-argc * 4000]; // BOOOM
+ // CHECK: is located 4000 bytes to the left of
+ free(x);
+ return res;
+}
diff --git a/test/asan/TestCases/init-order-atexit.cc b/test/asan/TestCases/init-order-atexit.cc
new file mode 100644
index 000000000000..e0dac325ce58
--- /dev/null
+++ b/test/asan/TestCases/init-order-atexit.cc
@@ -0,0 +1,34 @@
+// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316
+// XFAIL: android
+//
+// Test for the following situation:
+// (1) global A is constructed.
+// (2) exit() is called during construction of global B.
+// (3) destructor of A reads uninitialized global C from another module.
+// We do *not* want to report init-order bug in this case.
+
+// RUN: %clangxx_asan -O0 %s %p/Helpers/init-order-atexit-extra.cc -o %t
+// RUN: env ASAN_OPTIONS=strict_init_order=true not %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+
+void AccessC();
+
+class A {
+ public:
+ A() { }
+ ~A() { AccessC(); printf("PASSED\n"); }
+ // CHECK-NOT: AddressSanitizer
+ // CHECK: PASSED
+};
+
+A a;
+
+class B {
+ public:
+ B() { exit(1); }
+ ~B() { }
+};
+
+B b;
diff --git a/test/asan/TestCases/init-order-pthread-create.cc b/test/asan/TestCases/init-order-pthread-create.cc
new file mode 100644
index 000000000000..eeff308a4cd5
--- /dev/null
+++ b/test/asan/TestCases/init-order-pthread-create.cc
@@ -0,0 +1,32 @@
+// Check that init-order checking is properly disabled if pthread_create is
+// called.
+
+// RUN: %clangxx_asan %s %p/Helpers/init-order-pthread-create-extra.cc -pthread -o %t
+// RUN: env ASAN_OPTIONS=strict_init_order=true %run %t
+
+#include <stdio.h>
+#include <pthread.h>
+
+void *run(void *arg) {
+ return arg;
+}
+
+void *foo(void *input) {
+ pthread_t t;
+ pthread_create(&t, 0, run, input);
+ void *res;
+ pthread_join(t, &res);
+ return res;
+}
+
+void *bar(void *input) {
+ return input;
+}
+
+void *glob = foo((void*)0x1234);
+extern void *glob2;
+
+int main() {
+ printf("%p %p\n", glob, glob2);
+ return 0;
+}
diff --git a/test/asan/TestCases/initialization-blacklist.cc b/test/asan/TestCases/initialization-blacklist.cc
new file mode 100644
index 000000000000..8ea6b46c1833
--- /dev/null
+++ b/test/asan/TestCases/initialization-blacklist.cc
@@ -0,0 +1,29 @@
+// Test for blacklist functionality of initialization-order checker.
+
+// RUN: %clangxx_asan -O0 %s %p/Helpers/initialization-blacklist-extra.cc\
+// RUN: %p/Helpers/initialization-blacklist-extra2.cc \
+// RUN: -fsanitize-blacklist=%p/Helpers/initialization-blacklist.txt -o %t
+// RUN: env ASAN_OPTIONS=check_initialization_order=true %run %t 2>&1
+// RUN: %clangxx_asan -O1 %s %p/Helpers/initialization-blacklist-extra.cc\
+// RUN: %p/Helpers/initialization-blacklist-extra2.cc \
+// RUN: -fsanitize-blacklist=%p/Helpers/initialization-blacklist.txt -o %t
+// RUN: env ASAN_OPTIONS=check_initialization_order=true %run %t 2>&1
+// RUN: %clangxx_asan -O2 %s %p/Helpers/initialization-blacklist-extra.cc\
+// RUN: %p/Helpers/initialization-blacklist-extra2.cc \
+// RUN: -fsanitize-blacklist=%p/Helpers/initialization-blacklist.txt -o %t
+// RUN: env ASAN_OPTIONS=check_initialization_order=true %run %t 2>&1
+
+// Function is defined in another TU.
+int readBadGlobal();
+int x = readBadGlobal(); // init-order bug.
+
+// Function is defined in another TU.
+int accessBadObject();
+int y = accessBadObject(); // init-order bug.
+
+int readBadSrcGlobal();
+int z = readBadSrcGlobal(); // init-order bug.
+
+int main(int argc, char **argv) {
+ return argc + x + y + z - 1;
+}
diff --git a/test/asan/TestCases/initialization-bug.cc b/test/asan/TestCases/initialization-bug.cc
new file mode 100644
index 000000000000..badc6d1d1165
--- /dev/null
+++ b/test/asan/TestCases/initialization-bug.cc
@@ -0,0 +1,45 @@
+// Test to make sure basic initialization order errors are caught.
+
+// RUN: %clangxx_asan -O0 %s %p/Helpers/initialization-bug-extra2.cc -o %t
+// RUN: env ASAN_OPTIONS=check_initialization_order=true not %run %t 2>&1 | FileCheck %s
+
+// Do not test with optimization -- the error may be optimized away.
+
+// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=186
+// XFAIL: darwin
+
+#include <cstdio>
+
+// The structure of the test is:
+// "x", "y", "z" are dynamically initialized globals.
+// Value of "x" depends on "y", value of "y" depends on "z".
+// "x" and "z" are defined in this TU, "y" is defined in another one.
+// Thus we shoud stably report initialization order fiasco independently of
+// the translation unit order.
+
+int initZ() {
+ return 5;
+}
+int z = initZ();
+
+// 'y' is a dynamically initialized global residing in a different TU. This
+// dynamic initializer will read the value of 'y' before main starts. The
+// result is undefined behavior, which should be caught by initialization order
+// checking.
+extern int y;
+int __attribute__((noinline)) initX() {
+ return y + 1;
+ // CHECK: {{AddressSanitizer: initialization-order-fiasco}}
+ // CHECK: {{READ of size .* at 0x.* thread T0}}
+ // CHECK: {{0x.* is located 0 bytes inside of global variable .*(y|z).*}}
+}
+
+// This initializer begins our initialization order problems.
+static int x = initX();
+
+int main() {
+ // ASan should have caused an exit before main runs.
+ printf("PASS\n");
+ // CHECK-NOT: PASS
+ return 0;
+}
diff --git a/test/asan/TestCases/initialization-constexpr.cc b/test/asan/TestCases/initialization-constexpr.cc
new file mode 100644
index 000000000000..644246186e02
--- /dev/null
+++ b/test/asan/TestCases/initialization-constexpr.cc
@@ -0,0 +1,27 @@
+// Constexpr:
+// We need to check that a global variable initialized with a constexpr
+// constructor can be accessed during dynamic initialization (as a constexpr
+// constructor implies that it was initialized during constant initialization,
+// not dynamic initialization).
+
+// RUN: %clangxx_asan -O0 %s %p/Helpers/initialization-constexpr-extra.cc --std=c++11 -o %t
+// RUN: env ASAN_OPTIONS=check_initialization_order=true %run %t 2>&1
+// RUN: %clangxx_asan -O1 %s %p/Helpers/initialization-constexpr-extra.cc --std=c++11 -o %t
+// RUN: env ASAN_OPTIONS=check_initialization_order=true %run %t 2>&1
+// RUN: %clangxx_asan -O2 %s %p/Helpers/initialization-constexpr-extra.cc --std=c++11 -o %t
+// RUN: env ASAN_OPTIONS=check_initialization_order=true %run %t 2>&1
+// RUN: %clangxx_asan -O3 %s %p/Helpers/initialization-constexpr-extra.cc --std=c++11 -o %t
+// RUN: env ASAN_OPTIONS=check_initialization_order=true %run %t 2>&1
+
+class Integer {
+ private:
+ int value;
+
+ public:
+ constexpr Integer(int x = 0) : value(x) {}
+ int getValue() {return value;}
+};
+Integer coolestInteger(42);
+int getCoolestInteger() { return coolestInteger.getValue(); }
+
+int main() { return 0; }
diff --git a/test/asan/TestCases/initialization-nobug.cc b/test/asan/TestCases/initialization-nobug.cc
new file mode 100644
index 000000000000..1249deb425aa
--- /dev/null
+++ b/test/asan/TestCases/initialization-nobug.cc
@@ -0,0 +1,48 @@
+// A collection of various initializers which shouldn't trip up initialization
+// order checking. If successful, this will just return 0.
+
+// RUN: %clangxx_asan -O0 %s %p/Helpers/initialization-nobug-extra.cc -o %t
+// RUN: env ASAN_OPTIONS=check_initialization_order=true %run %t 2>&1
+// RUN: %clangxx_asan -O1 %s %p/Helpers/initialization-nobug-extra.cc -o %t
+// RUN: env ASAN_OPTIONS=check_initialization_order=true %run %t 2>&1
+// RUN: %clangxx_asan -O2 %s %p/Helpers/initialization-nobug-extra.cc -o %t
+// RUN: env ASAN_OPTIONS=check_initialization_order=true %run %t 2>&1
+// RUN: %clangxx_asan -O3 %s %p/Helpers/initialization-nobug-extra.cc -o %t
+// RUN: env ASAN_OPTIONS=check_initialization_order=true %run %t 2>&1
+
+// Simple access:
+// Make sure that accessing a global in the same TU is safe
+
+bool condition = true;
+int initializeSameTU() {
+ return condition ? 0x2a : 052;
+}
+int sameTU = initializeSameTU();
+
+// Linker initialized:
+// Check that access to linker initialized globals originating from a different
+// TU's initializer is safe.
+
+int A = (1 << 1) + (1 << 3) + (1 << 5), B;
+int getAB() {
+ return A * B;
+}
+
+// Function local statics:
+// Check that access to function local statics originating from a different
+// TU's initializer is safe.
+
+int countCalls() {
+ static int calls;
+ return ++calls;
+}
+
+// Trivial constructor, non-trivial destructor.
+struct StructWithDtor {
+ ~StructWithDtor() { }
+ int value;
+};
+StructWithDtor struct_with_dtor;
+int getStructWithDtorValue() { return struct_with_dtor.value; }
+
+int main() { return 0; }
diff --git a/test/asan/TestCases/inline.cc b/test/asan/TestCases/inline.cc
new file mode 100644
index 000000000000..daeb7b49eb22
--- /dev/null
+++ b/test/asan/TestCases/inline.cc
@@ -0,0 +1,19 @@
+// RUN: %clangxx_asan -O3 %s -o %t && %run %t
+
+// Test that no_sanitize_address attribute applies even when the function would
+// be normally inlined.
+
+#include <stdlib.h>
+
+__attribute__((no_sanitize_address))
+int f(int *p) {
+ return *p; // BOOOM?? Nope!
+}
+
+int main(int argc, char **argv) {
+ int * volatile x = (int*)malloc(2*sizeof(int) + 2);
+ int res = f(x + 2);
+ if (res)
+ exit(0);
+ return 0;
+}
diff --git a/test/asan/TestCases/interception_failure_test.cc b/test/asan/TestCases/interception_failure_test.cc
new file mode 100644
index 000000000000..a23fe6938ca9
--- /dev/null
+++ b/test/asan/TestCases/interception_failure_test.cc
@@ -0,0 +1,22 @@
+// If user provides his own libc functions, ASan doesn't
+// intercept these functions.
+
+// RUN: %clangxx_asan -O0 %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <stdlib.h>
+#include <stdio.h>
+
+extern "C" long strtol(const char *nptr, char **endptr, int base) {
+ fprintf(stderr, "my_strtol_interceptor\n");
+ return 0;
+}
+
+int main() {
+ char *x = (char*)malloc(10 * sizeof(char));
+ free(x);
+ return (int)strtol(x, 0, 10);
+ // CHECK: my_strtol_interceptor
+ // CHECK-NOT: heap-use-after-free
+}
diff --git a/test/asan/TestCases/interface_test.cc b/test/asan/TestCases/interface_test.cc
new file mode 100644
index 000000000000..dc9d0652c8c3
--- /dev/null
+++ b/test/asan/TestCases/interface_test.cc
@@ -0,0 +1,10 @@
+// Check that user may include ASan interface header.
+// RUN: %clang_asan %s -o %t && %run %t
+// RUN: %clang_asan -x c %s -o %t && %run %t
+// RUN: %clang %s -o %t && %run %t
+// RUN: %clang -x c %s -o %t && %run %t
+#include <sanitizer/asan_interface.h>
+
+int main() {
+ return 0;
+}
diff --git a/test/asan/TestCases/intra-object-overflow.cc b/test/asan/TestCases/intra-object-overflow.cc
new file mode 100644
index 000000000000..e48a261f55cc
--- /dev/null
+++ b/test/asan/TestCases/intra-object-overflow.cc
@@ -0,0 +1,31 @@
+// RUN: %clangxx_asan -O0 -fsanitize-address-field-padding=1 %s -o %t
+// RUN: not %run %t 11 2>&1 | FileCheck %s
+// RUN: %run %t 10
+//
+// FIXME: fix 32-bits.
+// REQUIRES: asan-64-bits
+#include <stdio.h>
+#include <stdlib.h>
+class Foo {
+ public:
+ Foo() : pre1(1), pre2(2), post1(3), post2(4) {
+ }
+ virtual ~Foo() {
+ }
+ void set(int i, int val) { a[i] = val; }
+// CHECK: ERROR: AddressSanitizer: intra-object-overflow
+// CHECK: #0 {{.*}}Foo::set{{.*}}intra-object-overflow.cc:[[@LINE-2]]
+ private:
+ int pre1, pre2;
+ int a[11];
+ int post1, post2;
+};
+
+int main(int argc, char **argv) {
+ int idx = argc == 2 ? atoi(argv[1]) : 0;
+ Foo *foo = new Foo;
+ foo->set(idx, 42);
+// CHECK: #1 {{.*}}main{{.*}}intra-object-overflow.cc:[[@LINE-1]]
+// CHECK: is located 84 bytes inside of 128-byte region
+ delete foo;
+}
diff --git a/test/asan/TestCases/invalid-free.cc b/test/asan/TestCases/invalid-free.cc
new file mode 100644
index 000000000000..cb545ccc215e
--- /dev/null
+++ b/test/asan/TestCases/invalid-free.cc
@@ -0,0 +1,23 @@
+// RUN: %clangxx_asan -O0 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=MALLOC-CTX
+
+// Also works if no malloc context is available.
+// RUN: env ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=0 not %run %t 2>&1 | FileCheck %s
+// RUN: env ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=1 not %run %t 2>&1 | FileCheck %s
+// XFAIL: arm-linux-gnueabi
+// XFAIL: armv7l-unknown-linux-gnueabihf
+
+#include <stdlib.h>
+#include <string.h>
+int main(int argc, char **argv) {
+ char *x = (char*)malloc(10 * sizeof(char));
+ memset(x, 0, 10);
+ int res = x[argc];
+ free(x + 5); // BOOM
+ // CHECK: AddressSanitizer: attempting free on address{{.*}}in thread T0
+ // CHECK: invalid-free.cc:[[@LINE-2]]
+ // CHECK: is located 5 bytes inside of 10-byte region
+ // CHECK: allocated by thread T0 here:
+ // MALLOC-CTX: invalid-free.cc:[[@LINE-8]]
+ return res;
+}
diff --git a/test/asan/TestCases/large_func_test.cc b/test/asan/TestCases/large_func_test.cc
new file mode 100644
index 000000000000..6b592f8c4397
--- /dev/null
+++ b/test/asan/TestCases/large_func_test.cc
@@ -0,0 +1,53 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
+// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
+// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
+// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
+// XFAIL: arm-linux-gnueabi
+// XFAIL: armv7l-unknown-linux-gnueabihf
+
+#include <stdlib.h>
+__attribute__((noinline))
+static void LargeFunction(int *x, int zero) {
+ x[0]++;
+ x[1]++;
+ x[2]++;
+ x[3]++;
+ x[4]++;
+ x[5]++;
+ x[6]++;
+ x[7]++;
+ x[8]++;
+ x[9]++;
+
+ // CHECK: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+ // CHECK: {{0x.* at pc 0x.* bp 0x.* sp 0x.*}}
+ // CHECK: {{READ of size 4 at 0x.* thread T0}}
+ x[zero + 103]++; // we should report this exact line
+ // atos incorrectly extracts the symbol name for the static functions on
+ // Darwin.
+ // CHECK-Linux: {{#0 0x.* in LargeFunction.*large_func_test.cc:}}[[@LINE-3]]
+ // CHECK-Darwin: {{#0 0x.* in .*LargeFunction.*large_func_test.cc}}:[[@LINE-4]]
+
+ x[10]++;
+ x[11]++;
+ x[12]++;
+ x[13]++;
+ x[14]++;
+ x[15]++;
+ x[16]++;
+ x[17]++;
+ x[18]++;
+ x[19]++;
+}
+
+int main(int argc, char **argv) {
+ int *x = new int[100];
+ LargeFunction(x, argc - 1);
+ // CHECK: {{ #1 0x.* in main .*large_func_test.cc:}}[[@LINE-1]]
+ // CHECK: {{0x.* is located 12 bytes to the right of 400-byte region}}
+ // CHECK: {{allocated by thread T0 here:}}
+ // CHECK-Linux: {{ #0 0x.* in operator new.*}}
+ // CHECK-Darwin: {{ #0 0x.* in .*_Zna.*}}
+ // CHECK: {{ #1 0x.* in main .*large_func_test.cc:}}[[@LINE-7]]
+ delete x;
+}
diff --git a/test/asan/TestCases/log-path_test.cc b/test/asan/TestCases/log-path_test.cc
new file mode 100644
index 000000000000..5a1d0729119a
--- /dev/null
+++ b/test/asan/TestCases/log-path_test.cc
@@ -0,0 +1,44 @@
+// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316
+// XFAIL: android
+//
+// RUN: %clangxx_asan %s -o %t
+
+// Regular run.
+// RUN: not %run %t 2> %t.out
+// RUN: FileCheck %s --check-prefix=CHECK-ERROR < %t.out
+
+// Good log_path.
+// RUN: rm -f %t.log.*
+// RUN: env ASAN_OPTIONS=log_path=%t.log not %run %t 2> %t.out
+// RUN: FileCheck %s --check-prefix=CHECK-ERROR < %t.log.*
+
+// Invalid log_path.
+// RUN: env ASAN_OPTIONS=log_path=/INVALID not %run %t 2> %t.out
+// RUN: FileCheck %s --check-prefix=CHECK-INVALID < %t.out
+
+// Too long log_path.
+// RUN: env ASAN_OPTIONS=log_path=`for((i=0;i<10000;i++)); do echo -n $i; done` \
+// RUN: not %run %t 2> %t.out
+// RUN: FileCheck %s --check-prefix=CHECK-LONG < %t.out
+
+// Run w/o errors should not produce any log.
+// RUN: rm -f %t.log.*
+// RUN: env ASAN_OPTIONS=log_path=%t.log %run %t ARG ARG ARG
+// RUN: not cat %t.log.*
+
+// FIXME: log_path is not supported on Windows yet.
+// XFAIL: win32
+
+#include <stdlib.h>
+#include <string.h>
+int main(int argc, char **argv) {
+ if (argc > 2) return 0;
+ char *x = (char*)malloc(10);
+ memset(x, 0, 10);
+ int res = x[argc * 10]; // BOOOM
+ free(x);
+ return res;
+}
+// CHECK-ERROR: ERROR: AddressSanitizer
+// CHECK-INVALID: ERROR: Can't open file: /INVALID
+// CHECK-LONG: ERROR: Path is too long: 01234
diff --git a/test/asan/TestCases/log_path_fork_test.cc.disabled b/test/asan/TestCases/log_path_fork_test.cc.disabled
new file mode 100644
index 000000000000..cfe90dfb54d3
--- /dev/null
+++ b/test/asan/TestCases/log_path_fork_test.cc.disabled
@@ -0,0 +1,22 @@
+// RUN: %clangxx_asan %s -o %t
+// RUN: rm -f %t.log.*
+// Set verbosity to 1 so that the log files are opened prior to fork().
+// RUN: env ASAN_OPTIONS="log_path=%t.log verbosity=1" not %run %t 2> %t.out
+// RUN: for f in %t.log.* ; do FileCheck %s < $f; done
+// RUN: [ `ls %t.log.* | wc -l` == 2 ]
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int main(int argc, char **argv) {
+ void *x = malloc(10);
+ free(x);
+ if (fork() == -1) return 1;
+ // There are two processes at this point, thus there should be two distinct
+ // error logs.
+ free(x);
+ return 0;
+}
+
+// CHECK: ERROR: AddressSanitizer
diff --git a/test/asan/TestCases/longjmp.cc b/test/asan/TestCases/longjmp.cc
new file mode 100644
index 000000000000..8e9f2ae195c7
--- /dev/null
+++ b/test/asan/TestCases/longjmp.cc
@@ -0,0 +1,25 @@
+// RUN: %clangxx_asan -O %s -o %t && %run %t
+
+#include <assert.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <sanitizer/asan_interface.h>
+
+static jmp_buf buf;
+
+int main() {
+ char x[32];
+ fprintf(stderr, "\nTestLongJmp\n");
+ fprintf(stderr, "Before: %p poisoned: %d\n", &x,
+ __asan_address_is_poisoned(x + 32));
+ assert(__asan_address_is_poisoned(x + 32));
+ if (0 == setjmp(buf))
+ longjmp(buf, 1);
+ 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
+ // This assertion works only w/o UAR.
+ if (!__asan_get_current_fake_stack())
+ assert(!__asan_address_is_poisoned(x + 32));
+}
diff --git a/test/asan/TestCases/lsan_annotations.cc b/test/asan/TestCases/lsan_annotations.cc
new file mode 100644
index 000000000000..f52b0ff66a8d
--- /dev/null
+++ b/test/asan/TestCases/lsan_annotations.cc
@@ -0,0 +1,16 @@
+// Check that LSan annotations work fine.
+// RUN: %clangxx_asan -O0 %s -o %t && %run %t
+// RUN: %clangxx_asan -O3 %s -o %t && %run %t
+
+#include <sanitizer/lsan_interface.h>
+#include <stdlib.h>
+
+int main() {
+ int *x = new int;
+ __lsan_ignore_object(x);
+ {
+ __lsan::ScopedDisabler disabler;
+ double *y = new double;
+ }
+ return 0;
+}
diff --git a/test/asan/TestCases/malloc_context_size.cc b/test/asan/TestCases/malloc_context_size.cc
new file mode 100644
index 000000000000..0d9f31598545
--- /dev/null
+++ b/test/asan/TestCases/malloc_context_size.cc
@@ -0,0 +1,27 @@
+// RUN: %clangxx_asan -O0 %s -o %t
+// RUN: env ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=0 not %run %t 2>&1 | FileCheck %s
+// RUN: env ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=1 not %run %t 2>&1 | FileCheck %s
+// RUN: env ASAN_OPTIONS=malloc_context_size=1:fast_unwind_on_malloc=0 not %run %t 2>&1 | FileCheck %s
+// RUN: env ASAN_OPTIONS=malloc_context_size=1:fast_unwind_on_malloc=1 not %run %t 2>&1 | FileCheck %s
+// RUN: env ASAN_OPTIONS=malloc_context_size=2 not %run %t 2>&1 | FileCheck %s --check-prefix=TWO
+
+int main() {
+ char *x = new char[20];
+ delete[] x;
+ return x[0];
+
+ // CHECK: freed by thread T{{.*}} here:
+ // CHECK-NEXT: #0 0x{{.*}} in {{operator delete( )?\[\]|wrap__ZdaPv}}
+ // CHECK-NOT: #1 0x{{.*}}
+
+ // CHECK: previously allocated by thread T{{.*}} here:
+ // CHECK-NEXT: #0 0x{{.*}} in {{operator new( )?\[\]|wrap__Znam}}
+ // CHECK-NOT: #1 0x{{.*}}
+
+ // CHECK: SUMMARY: AddressSanitizer: heap-use-after-free
+
+ // TWO: previously allocated by thread T{{.*}} here:
+ // TWO-NEXT: #0 0x{{.*}}
+ // TWO-NEXT: #1 0x{{.*}} in main {{.*}}malloc_context_size.cc
+ // TWO: SUMMARY: AddressSanitizer: heap-use-after-free
+}
diff --git a/test/asan/TestCases/malloc_fill.cc b/test/asan/TestCases/malloc_fill.cc
new file mode 100644
index 000000000000..5c926803708d
--- /dev/null
+++ b/test/asan/TestCases/malloc_fill.cc
@@ -0,0 +1,22 @@
+// Check that we fill malloc-ed memory correctly.
+// RUN: %clangxx_asan %s -o %t
+// RUN: %run %t | FileCheck %s
+// RUN: env ASAN_OPTIONS=max_malloc_fill_size=10:malloc_fill_byte=8 %run %t | FileCheck %s --check-prefix=CHECK-10-8
+// RUN: env ASAN_OPTIONS=max_malloc_fill_size=20:malloc_fill_byte=171 %run %t | FileCheck %s --check-prefix=CHECK-20-ab
+
+#include <stdio.h>
+int main(int argc, char **argv) {
+ // With asan allocator this makes sure we get memory from mmap.
+ static const int kSize = 1 << 25;
+ unsigned char *x = new unsigned char[kSize];
+ printf("-");
+ for (int i = 0; i <= 32; i++) {
+ printf("%02x", x[i]);
+ }
+ printf("-\n");
+ delete [] x;
+}
+
+// CHECK: -bebebebebebebebebebebebebebebebebebebebebebebebebebebebebebebebebe-
+// CHECK-10-8: -080808080808080808080000000000000000000000000000000000000000000000-
+// CHECK-20-ab: -abababababababababababababababababababab00000000000000000000000000-
diff --git a/test/asan/TestCases/max_redzone.cc b/test/asan/TestCases/max_redzone.cc
new file mode 100644
index 000000000000..01c25a9f3efc
--- /dev/null
+++ b/test/asan/TestCases/max_redzone.cc
@@ -0,0 +1,26 @@
+// Test max_redzone runtime option.
+
+// RUN: %clangxx_asan -O0 %s -o %t && env ASAN_OPTIONS=max_redzone=16 %run %t 0 2>&1
+// RUN: %clangxx_asan -O0 %s -o %t && %run %t 1 2>&1
+// RUN: %clangxx_asan -O3 %s -o %t && env ASAN_OPTIONS=max_redzone=16 %run %t 0 2>&1
+// RUN: %clangxx_asan -O3 %s -o %t && %run %t 1 2>&1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sanitizer/allocator_interface.h>
+
+int main(int argc, char **argv) {
+ if (argc < 2)
+ return 1;
+ bool large_redzone = atoi(argv[1]);
+ size_t before = __sanitizer_get_heap_size();
+ void *pp[10000];
+ for (int i = 0; i < 10000; ++i)
+ pp[i] = malloc(4096 - 64);
+ size_t after = __sanitizer_get_heap_size();
+ for (int i = 0; i < 10000; ++i)
+ free(pp[i]);
+ size_t diff = after - before;
+ return !(large_redzone ? diff > 46000000 : diff < 46000000);
+}
diff --git a/test/asan/TestCases/memcmp_strict_test.cc b/test/asan/TestCases/memcmp_strict_test.cc
new file mode 100644
index 000000000000..16b7673dd547
--- /dev/null
+++ b/test/asan/TestCases/memcmp_strict_test.cc
@@ -0,0 +1,15 @@
+// RUN: %clangxx_asan -O0 %s -o %t && env ASAN_OPTIONS=strict_memcmp=0 %run %t
+// RUN: %clangxx_asan -O0 %s -o %t && env ASAN_OPTIONS=strict_memcmp=1 not %run %t 2>&1 | FileCheck %s
+// Default to strict_memcmp=1.
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <string.h>
+int main() {
+ char kFoo[] = "foo";
+ char kFubar[] = "fubar";
+ int res = memcmp(kFoo, kFubar, strlen(kFubar));
+ printf("res: %d\n", res);
+ // CHECK: AddressSanitizer: stack-buffer-overflow
+ return 0;
+}
diff --git a/test/asan/TestCases/memcmp_test.cc b/test/asan/TestCases/memcmp_test.cc
new file mode 100644
index 000000000000..3b3b8894b73c
--- /dev/null
+++ b/test/asan/TestCases/memcmp_test.cc
@@ -0,0 +1,17 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// 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
+
+// REQUIRES: compiler-rt-optimized
+
+#include <string.h>
+int main(int argc, char **argv) {
+ char a1[] = {argc, 2, 3, 4};
+ char a2[] = {1, 2*argc, 3, 4};
+ int res = memcmp(a1, a2, 4 + argc); // BOOM
+ // CHECK: AddressSanitizer: stack-buffer-overflow
+ // CHECK: {{#0.*memcmp}}
+ // CHECK: {{#1.*main}}
+ return res;
+}
diff --git a/test/asan/TestCases/memset_test.cc b/test/asan/TestCases/memset_test.cc
new file mode 100644
index 000000000000..e244d54deb3c
--- /dev/null
+++ b/test/asan/TestCases/memset_test.cc
@@ -0,0 +1,71 @@
+// Test that large memset/memcpy/memmove check the entire range.
+
+// RUN: %clangxx_asan -O0 -DTEST_MEMSET %s -o %t && not %run %t 2>&1 | \
+// RUN: FileCheck %s --check-prefix=CHECK-MEMSET
+// RUN: %clangxx_asan -O1 -DTEST_MEMSET %s -o %t && not %run %t 2>&1 | \
+// RUN: FileCheck %s --check-prefix=CHECK-MEMSET
+// RUN: %clangxx_asan -O2 -DTEST_MEMSET %s -o %t && not %run %t 2>&1 | \
+// RUN: FileCheck %s --check-prefix=CHECK-MEMSET
+// RUN: %clangxx_asan -O3 -DTEST_MEMSET %s -o %t && not %run %t 2>&1 | \
+// RUN: FileCheck %s --check-prefix=CHECK-MEMSET
+
+// RUN: %clangxx_asan -O0 -DTEST_MEMCPY %s -o %t && not %run %t 2>&1 | \
+// RUN: FileCheck %s --check-prefix=CHECK-MEMCPY
+// RUN: %clangxx_asan -O1 -DTEST_MEMCPY %s -o %t && not %run %t 2>&1 | \
+// RUN: FileCheck %s --check-prefix=CHECK-MEMCPY
+// RUN: %clangxx_asan -O2 -DTEST_MEMCPY %s -o %t && not %run %t 2>&1 | \
+// RUN: FileCheck %s --check-prefix=CHECK-MEMCPY
+// RUN: %clangxx_asan -O3 -DTEST_MEMCPY %s -o %t && not %run %t 2>&1 | \
+// RUN: FileCheck %s --check-prefix=CHECK-MEMCPY
+
+// RUN: %clangxx_asan -O0 -DTEST_MEMMOVE %s -o %t && not %run %t 2>&1 | \
+// RUN: FileCheck %s --check-prefix=CHECK-MEMMOVE
+// RUN: %clangxx_asan -O1 -DTEST_MEMMOVE %s -o %t && not %run %t 2>&1 | \
+// RUN: FileCheck %s --check-prefix=CHECK-MEMMOVE
+// RUN: %clangxx_asan -O2 -DTEST_MEMMOVE %s -o %t && not %run %t 2>&1 | \
+// RUN: FileCheck %s --check-prefix=CHECK-MEMMOVE
+// RUN: %clangxx_asan -O3 -DTEST_MEMMOVE %s -o %t && not %run %t 2>&1 | \
+// RUN: FileCheck %s --check-prefix=CHECK-MEMMOVE
+
+// RUN: %clangxx_asan -O2 -DTEST_MEMCPY_SIZE_OVERFLOW %s -o %t && not %run %t 2>&1 | \
+// RUN: FileCheck %s --check-prefix=CHECK-MEMCPY_SIZE_OVERFLOW
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <sanitizer/asan_interface.h>
+
+typedef void *(*memcpy_t)(void *, const void *, size_t);
+
+int main(int argc, char **argv) {
+ char * volatile p = (char *)malloc(3000);
+ __asan_poison_memory_region(p + 512, 16);
+#if defined(TEST_MEMSET)
+ memset(p, 0, 3000);
+ assert(p[1] == 0);
+ // CHECK-MEMSET: AddressSanitizer: use-after-poison on address
+ // CHECK-MEMSET: in {{.*}}memset
+#else
+ char * volatile q = (char *)malloc(3000);
+#if defined(TEST_MEMCPY)
+ memcpy(q, p, 3000);
+ // CHECK-MEMCPY: AddressSanitizer: use-after-poison on address
+ // On Mac, memmove and memcpy are the same. Accept either one.
+ // CHECK-MEMCPY: in {{.*(memmove|memcpy)}}
+#elif defined(TEST_MEMMOVE)
+ memmove(q, p, 3000);
+ // CHECK-MEMMOVE: AddressSanitizer: use-after-poison on address
+ // CHECK-MEMMOVE: in {{.*(memmove|memcpy)}}
+#elif defined(TEST_MEMCPY_SIZE_OVERFLOW)
+ volatile memcpy_t my_memcpy = &memcpy;
+ my_memcpy(p, q, -argc);
+ // CHECK-MEMCPY_SIZE_OVERFLOW: AddressSanitizer: negative-size-param: (size=-1)
+#endif
+ assert(q[1] == 0);
+ free(q);
+#endif
+ free(p);
+ return 0;
+}
diff --git a/test/asan/TestCases/mmap_limit_mb.cc b/test/asan/TestCases/mmap_limit_mb.cc
new file mode 100644
index 000000000000..d4ffb2eac246
--- /dev/null
+++ b/test/asan/TestCases/mmap_limit_mb.cc
@@ -0,0 +1,33 @@
+// Test the mmap_limit_mb flag.
+//
+// RUN: %clangxx_asan -O2 %s -o %t
+// RUN: %run %t 20 16
+// RUN: %run %t 30 1000000
+// RUN: env ASAN_OPTIONS=mmap_limit_mb=300 %run %t 20 16
+// RUN: env ASAN_OPTIONS=mmap_limit_mb=300 %run %t 20 1000000
+// RUN: env ASAN_OPTIONS=mmap_limit_mb=300 not %run %t 500 16 2>&1 | FileCheck %s
+// RUN: env ASAN_OPTIONS=mmap_limit_mb=300 not %run %t 500 1000000 2>&1 | FileCheck %s
+// XFAIL: arm-linux-gnueabi
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <algorithm>
+#include <vector>
+
+int main(int argc, char **argv) {
+ assert(argc == 3);
+ long total_mb = atoi(argv[1]);
+ long allocation_size = atoi(argv[2]);
+ fprintf(stderr, "total_mb: %zd allocation_size: %zd\n", total_mb,
+ allocation_size);
+ std::vector<char *> v;
+ for (long total = total_mb << 20; total > 0; total -= allocation_size)
+ v.push_back(new char[allocation_size]);
+ for (std::vector<char *>::const_iterator it = v.begin(); it != v.end(); ++it)
+ delete[](*it);
+ fprintf(stderr, "PASS\n");
+ // CHECK: total_mmaped{{.*}}mmap_limit_mb
+ return 0;
+}
diff --git a/test/asan/TestCases/no_asan_gen_globals.c b/test/asan/TestCases/no_asan_gen_globals.c
new file mode 100644
index 000000000000..0a383da1384d
--- /dev/null
+++ b/test/asan/TestCases/no_asan_gen_globals.c
@@ -0,0 +1,11 @@
+// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316
+// XFAIL: android
+//
+// Make sure __asan_gen_* strings do not end up in the symbol table.
+
+// RUN: %clang_asan %s -o %t.exe
+// RUN: nm %t.exe | FileCheck %s
+
+int x, y, z;
+int main() { return 0; }
+// CHECK-NOT: __asan_gen_
diff --git a/test/asan/TestCases/null_deref.cc b/test/asan/TestCases/null_deref.cc
new file mode 100644
index 000000000000..875d65f2852f
--- /dev/null
+++ b/test/asan/TestCases/null_deref.cc
@@ -0,0 +1,19 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// 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
+
+__attribute__((noinline))
+static void NullDeref(int *ptr) {
+ // CHECK: ERROR: AddressSanitizer: SEGV on unknown address
+ // CHECK: {{0x0*000.. .*pc 0x.*}}
+ ptr[10]++; // BOOM
+ // atos on Mac cannot extract the symbol name correctly. Also, on FreeBSD 9.2
+ // the demangling function rejects local names with 'L' in front of them.
+ // CHECK: {{ #0 0x.* in .*NullDeref.*null_deref.cc:}}[[@LINE-3]]
+}
+int main() {
+ NullDeref((int*)0);
+ // CHECK: {{ #1 0x.* in main.*null_deref.cc:}}[[@LINE-1]]
+ // CHECK: AddressSanitizer can not provide additional info.
+}
diff --git a/test/asan/TestCases/on_error_callback.cc b/test/asan/TestCases/on_error_callback.cc
new file mode 100644
index 000000000000..c378c8b2de1b
--- /dev/null
+++ b/test/asan/TestCases/on_error_callback.cc
@@ -0,0 +1,19 @@
+// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+// FIXME: __asan_on_error() is not supported on Windows yet.
+// XFAIL: win32
+
+#include <stdio.h>
+#include <stdlib.h>
+
+extern "C"
+void __asan_on_error() {
+ fprintf(stderr, "__asan_on_error called");
+}
+
+int main() {
+ char *x = (char*)malloc(10 * sizeof(char));
+ free(x);
+ return x[5];
+ // CHECK: __asan_on_error called
+}
diff --git a/test/asan/TestCases/partial_right.cc b/test/asan/TestCases/partial_right.cc
new file mode 100644
index 000000000000..b60c1a597635
--- /dev/null
+++ b/test/asan/TestCases/partial_right.cc
@@ -0,0 +1,13 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// 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
+
+#include <stdlib.h>
+int main(int argc, char **argv) {
+ volatile int *x = (int*)malloc(2*sizeof(int) + 2);
+ int res = x[2]; // BOOOM
+ // CHECK: {{READ of size 4 at 0x.* thread T0}}
+ // CHECK: [[ADDR:0x[01-9a-fa-f]+]] is located 0 bytes to the right of {{.*}}-byte region [{{.*}},{{.*}}[[ADDR]])
+ return res;
+}
diff --git a/test/asan/TestCases/poison_partial.cc b/test/asan/TestCases/poison_partial.cc
new file mode 100644
index 000000000000..ce9c98b7859a
--- /dev/null
+++ b/test/asan/TestCases/poison_partial.cc
@@ -0,0 +1,19 @@
+// RUN: %clangxx_asan -O0 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: not %run %t heap 2>&1 | FileCheck %s
+// RUN: env ASAN_OPTIONS=poison_partial=0 %run %t
+// RUN: env ASAN_OPTIONS=poison_partial=0 %run %t heap
+#include <string.h>
+char g[21];
+char *x;
+
+int main(int argc, char **argv) {
+ if (argc >= 2)
+ x = new char[21];
+ else
+ x = &g[0];
+ memset(x, 0, 21);
+ int *y = (int*)x;
+ return y[5];
+}
+// CHECK: 0 bytes to the right
diff --git a/test/asan/TestCases/print_summary.cc b/test/asan/TestCases/print_summary.cc
new file mode 100644
index 000000000000..79411c529469
--- /dev/null
+++ b/test/asan/TestCases/print_summary.cc
@@ -0,0 +1,14 @@
+// RUN: %clangxx_asan -O0 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=YES
+// RUN: env ASAN_OPTIONS=print_summary=false not %run %t 2>&1 | FileCheck %s --check-prefix=NO
+
+int main() {
+ char *x = new char[20];
+ delete[] x;
+ return x[0];
+ // YES: ERROR: AddressSanitizer: heap-use-after-free
+ // YES: SUMMARY: AddressSanitizer: heap-use-after-free
+ // NO: ERROR: AddressSanitizer: heap-use-after-free
+ // NO-NOT: SUMMARY: AddressSanitizer: heap-use-after-free
+}
+
diff --git a/test/asan/TestCases/printf-1.c b/test/asan/TestCases/printf-1.c
new file mode 100644
index 000000000000..5657083c5865
--- /dev/null
+++ b/test/asan/TestCases/printf-1.c
@@ -0,0 +1,25 @@
+// RUN: %clang_asan -O2 %s -o %t
+// RUN: env ASAN_OPTIONS=check_printf=1 %run %t 2>&1 | FileCheck %s
+// RUN: env ASAN_OPTIONS=check_printf=0 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#if defined(_WIN32)
+# define snprintf _snprintf
+#endif
+
+int main() {
+ volatile char c = '0';
+ volatile int x = 12;
+ volatile float f = 1.239;
+ volatile char s[] = "34";
+ // Check that printf works fine under Asan.
+ printf("%c %d %.3f %s\n", c, x, f, s);
+ // CHECK: 0 12 1.239 34
+ // Check that snprintf works fine under Asan.
+ char buf[4];
+ snprintf(buf, 1000, "qwe");
+ printf("%s\n", buf);
+ // CHECK: qwe
+ return 0;
+}
diff --git a/test/asan/TestCases/printf-2.c b/test/asan/TestCases/printf-2.c
new file mode 100644
index 000000000000..e9cb47e24c15
--- /dev/null
+++ b/test/asan/TestCases/printf-2.c
@@ -0,0 +1,27 @@
+// 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_OPTIONS=replace_str=0:replace_intrin=0:check_printf=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-ON %s
+// RUN: env ASAN_OPTIONS=replace_str=0:replace_intrin=0:check_printf=0 %run %t 2>&1 | FileCheck --check-prefix=CHECK-OFF %s
+// RUN: env ASAN_OPTIONS=replace_str=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
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+int main() {
+ volatile char c = '0';
+ volatile int x = 12;
+ volatile float f = 1.239;
+ volatile char s[] = "34";
+ char *p = strdup((const char *)s);
+ free(p);
+ printf("%c %d %.3f %s\n", c, x, f, p);
+ return 0;
+ // Check that %s is sanitized.
+ // CHECK-ON: heap-use-after-free
+ // CHECK-ON-NOT: 0 12 1.239 34
+ // CHECK-OFF: 0 12 1.239
+}
diff --git a/test/asan/TestCases/printf-3.c b/test/asan/TestCases/printf-3.c
new file mode 100644
index 000000000000..d16833d83c6e
--- /dev/null
+++ b/test/asan/TestCases/printf-3.c
@@ -0,0 +1,22 @@
+// RUN: %clang_asan -O2 %s -o %t
+// RUN: env ASAN_OPTIONS=check_printf=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-ON %s
+// RUN: env ASAN_OPTIONS=check_printf=0 %run %t 2>&1 | FileCheck --check-prefix=CHECK-OFF %s
+// RUN: not %run %t 2>&1 | FileCheck --check-prefix=CHECK-ON %s
+
+// FIXME: printf is not intercepted on Windows yet.
+// XFAIL: win32
+
+#include <stdio.h>
+int main() {
+ volatile char c = '0';
+ volatile int x = 12;
+ volatile float f = 1.239;
+ volatile char s[] = "34";
+ volatile int n[1];
+ printf("%c %d %.3f %s%n\n", c, x, f, s, &n[1]);
+ return 0;
+ // Check that %n is sanitized.
+ // CHECK-ON: stack-buffer-overflow
+ // CHECK-ON-NOT: 0 12 1.239 34
+ // CHECK-OFF: 0 12 1.239 34
+}
diff --git a/test/asan/TestCases/printf-4.c b/test/asan/TestCases/printf-4.c
new file mode 100644
index 000000000000..e269211d4871
--- /dev/null
+++ b/test/asan/TestCases/printf-4.c
@@ -0,0 +1,23 @@
+// 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_OPTIONS=replace_str=0:replace_intrin=0:check_printf=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-ON %s
+// RUN: env ASAN_OPTIONS=replace_str=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
+
+#include <stdio.h>
+int main() {
+ volatile char c = '0';
+ volatile int x = 12;
+ volatile float f = 1.239;
+ volatile char s[] = "34";
+ volatile char buf[2];
+ sprintf((char *)buf, "%c %d %.3f %s\n", c, x, f, s);
+ puts((const char *)buf);
+ return 0;
+ // Check that size of output buffer is sanitized.
+ // CHECK-ON: stack-buffer-overflow
+ // CHECK-ON-NOT: 0 12 1.239 34
+}
diff --git a/test/asan/TestCases/printf-5.c b/test/asan/TestCases/printf-5.c
new file mode 100644
index 000000000000..ac2c1c4b2997
--- /dev/null
+++ b/test/asan/TestCases/printf-5.c
@@ -0,0 +1,25 @@
+// RUN: %clang_asan -O2 %s -o %t
+// We need replace_intrin=0 to avoid reporting errors in memcpy.
+// RUN: env ASAN_OPTIONS=replace_intrin=0:check_printf=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-ON %s
+// RUN: env ASAN_OPTIONS=replace_intrin=0:check_printf=0 %run %t 2>&1 | FileCheck --check-prefix=CHECK-OFF %s
+// RUN: env ASAN_OPTIONS=replace_intrin=0 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-ON %s
+
+// FIXME: printf is not intercepted on Windows yet.
+// XFAIL: win32
+
+#include <stdio.h>
+#include <string.h>
+int main() {
+ volatile char c = '0';
+ volatile int x = 12;
+ volatile float f = 1.239;
+ volatile char s[] = "34";
+ volatile char fmt[2];
+ memcpy((char *)fmt, "%c %d %f %s\n", sizeof(fmt));
+ printf((char *)fmt, c, x, f, s);
+ return 0;
+ // Check that format string is sanitized.
+ // CHECK-ON: stack-buffer-overflow
+ // CHECK-ON-NOT: 0 12 1.239 34
+ // CHECK-OFF: 0
+}
diff --git a/test/asan/TestCases/sanity_check_pure_c.c b/test/asan/TestCases/sanity_check_pure_c.c
new file mode 100644
index 000000000000..c3a43c8cacb2
--- /dev/null
+++ b/test/asan/TestCases/sanity_check_pure_c.c
@@ -0,0 +1,21 @@
+// Sanity checking a test in pure C.
+// RUN: %clang_asan -O2 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+// Sanity checking a test in pure C with -pie.
+// RUN: %clang_asan -O2 %s -pie -fPIE -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// XFAIL: arm-linux-gnueabi
+// XFAIL: armv7l-unknown-linux-gnueabihf
+
+#include <stdlib.h>
+int main() {
+ char *x = (char*)malloc(10 * sizeof(char));
+ free(x);
+ return x[5];
+ // CHECK: heap-use-after-free
+ // CHECK: free
+ // CHECK: main{{.*}}sanity_check_pure_c.c:[[@LINE-4]]
+ // CHECK: malloc
+ // CHECK: main{{.*}}sanity_check_pure_c.c:[[@LINE-7]]
+}
diff --git a/test/asan/TestCases/sleep_before_dying.c b/test/asan/TestCases/sleep_before_dying.c
new file mode 100644
index 000000000000..28ae0bf66d47
--- /dev/null
+++ b/test/asan/TestCases/sleep_before_dying.c
@@ -0,0 +1,10 @@
+// RUN: %clang_asan -O2 %s -o %t
+// RUN: env ASAN_OPTIONS="sleep_before_dying=1" not %run %t 2>&1 | FileCheck %s
+
+#include <stdlib.h>
+int main() {
+ char *x = (char*)malloc(10 * sizeof(char));
+ free(x);
+ return x[5];
+ // CHECK: Sleeping for 1 second
+}
diff --git a/test/asan/TestCases/stack-buffer-overflow-with-position.cc b/test/asan/TestCases/stack-buffer-overflow-with-position.cc
new file mode 100644
index 000000000000..88f5825baf42
--- /dev/null
+++ b/test/asan/TestCases/stack-buffer-overflow-with-position.cc
@@ -0,0 +1,44 @@
+// RUN: %clangxx_asan -O2 %s -o %t
+// RUN: not %run %t -2 2>&1 | FileCheck --check-prefix=CHECK-m2 %s
+// RUN: not %run %t -1 2>&1 | FileCheck --check-prefix=CHECK-m1 %s
+// RUN: %run %t 0
+// RUN: %run %t 8
+// RUN: not %run %t 9 2>&1 | FileCheck --check-prefix=CHECK-9 %s
+// RUN: not %run %t 10 2>&1 | FileCheck --check-prefix=CHECK-10 %s
+// RUN: not %run %t 30 2>&1 | FileCheck --check-prefix=CHECK-30 %s
+// RUN: not %run %t 31 2>&1 | FileCheck --check-prefix=CHECK-31 %s
+// RUN: not %run %t 41 2>&1 | FileCheck --check-prefix=CHECK-41 %s
+// RUN: not %run %t 42 2>&1 | FileCheck --check-prefix=CHECK-42 %s
+// RUN: not %run %t 62 2>&1 | FileCheck --check-prefix=CHECK-62 %s
+// RUN: not %run %t 63 2>&1 | FileCheck --check-prefix=CHECK-63 %s
+// RUN: not %run %t 73 2>&1 | FileCheck --check-prefix=CHECK-73 %s
+// RUN: not %run %t 74 2>&1 | FileCheck --check-prefix=CHECK-74 %s
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+int main(int argc, char **argv) {
+ assert(argc >= 2);
+ int idx = atoi(argv[1]);
+ char AAA[10], BBB[10], CCC[10];
+ memset(AAA, 0, sizeof(AAA));
+ memset(BBB, 0, sizeof(BBB));
+ memset(CCC, 0, sizeof(CCC));
+ int res = 0;
+ char *p = AAA + idx;
+ printf("AAA: %p\ny: %p\nz: %p\np: %p\n", AAA, BBB, CCC, p);
+ // make sure BBB and CCC are not removed;
+ return *(short*)(p) + BBB[argc % 2] + CCC[argc % 2];
+}
+// CHECK-m2: 'AAA' <== {{.*}}underflows this variable
+// CHECK-m1: 'AAA' <== {{.*}}partially underflows this variable
+// CHECK-9: 'AAA' <== {{.*}}partially overflows this variable
+// CHECK-10: 'AAA' <== {{.*}}overflows this variable
+// CHECK-30: 'BBB' <== {{.*}}underflows this variable
+// CHECK-31: 'BBB' <== {{.*}}partially underflows this variable
+// CHECK-41: 'BBB' <== {{.*}}partially overflows this variable
+// CHECK-42: 'BBB' <== {{.*}}overflows this variable
+// CHECK-62: 'CCC' <== {{.*}}underflows this variable
+// CHECK-63: 'CCC' <== {{.*}}partially underflows this variable
+// CHECK-73: 'CCC' <== {{.*}}partially overflows this variable
+// CHECK-74: 'CCC' <== {{.*}}overflows this variable
diff --git a/test/asan/TestCases/stack-buffer-overflow.cc b/test/asan/TestCases/stack-buffer-overflow.cc
new file mode 100644
index 000000000000..bd0c4772cc84
--- /dev/null
+++ b/test/asan/TestCases/stack-buffer-overflow.cc
@@ -0,0 +1,16 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// 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
+
+#include <string.h>
+int main(int argc, char **argv) {
+ char x[10];
+ memset(x, 0, 10);
+ int res = x[argc * 10]; // BOOOM
+ // CHECK: {{READ of size 1 at 0x.* thread T0}}
+ // CHECK: {{ #0 0x.* in main .*stack-buffer-overflow.cc:}}[[@LINE-2]]
+ // CHECK: {{Address 0x.* is located in stack of thread T0 at offset}}
+ // CHECK-NEXT: in{{.*}}main{{.*}}stack-buffer-overflow.cc
+ return res;
+}
diff --git a/test/asan/TestCases/stack-frame-demangle.cc b/test/asan/TestCases/stack-frame-demangle.cc
new file mode 100644
index 000000000000..11a8b38e6724
--- /dev/null
+++ b/test/asan/TestCases/stack-frame-demangle.cc
@@ -0,0 +1,22 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+#include <string.h>
+
+namespace XXX {
+struct YYY {
+ static int ZZZ(int x) {
+ char array[10];
+ memset(array, 0, 10);
+ return array[x]; // BOOOM
+ // CHECK: ERROR: AddressSanitizer: stack-buffer-overflow
+ // CHECK: READ of size 1 at
+ // CHECK: is located in stack of thread T0 at offset
+ // CHECK: XXX::YYY::ZZZ
+ }
+};
+} // namespace XXX
+
+int main(int argc, char **argv) {
+ int res = XXX::YYY::ZZZ(argc + 10);
+ return res;
+}
diff --git a/test/asan/TestCases/stack-oob-frames.cc b/test/asan/TestCases/stack-oob-frames.cc
new file mode 100644
index 000000000000..3b5d511b2681
--- /dev/null
+++ b/test/asan/TestCases/stack-oob-frames.cc
@@ -0,0 +1,59 @@
+// RUN: %clangxx_asan -O1 %s -o %t
+// RUN: not %run %t 0 2>&1 | FileCheck %s --check-prefix=CHECK0
+// 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
+
+#define NOINLINE __attribute__((noinline))
+inline void break_optimization(void *arg) {
+ __asm__ __volatile__("" : : "r" (arg) : "memory");
+}
+
+NOINLINE static void Frame0(int frame, char *a, char *b, char *c) {
+ char s[4] = {0};
+ char *d = s;
+ break_optimization(&d);
+ switch (frame) {
+ case 3: a[5]++; break;
+ case 2: b[5]++; break;
+ case 1: c[5]++; break;
+ case 0: d[5]++; break;
+ }
+}
+NOINLINE static void Frame1(int frame, char *a, char *b) {
+ char c[4] = {0}; Frame0(frame, a, b, c);
+ break_optimization(0);
+}
+NOINLINE static void Frame2(int frame, char *a) {
+ char b[4] = {0}; Frame1(frame, a, b);
+ break_optimization(0);
+}
+NOINLINE static void Frame3(int frame) {
+ char a[4] = {0}; Frame2(frame, a);
+ break_optimization(0);
+}
+
+int main(int argc, char **argv) {
+ if (argc != 2) return 1;
+ Frame3(argv[1][0] - '0');
+}
+
+// CHECK0: AddressSanitizer: stack-buffer-overflow
+// CHECK0: #0{{.*}}Frame0
+// CHECK0: #1{{.*}}Frame1
+// CHECK0: #2{{.*}}Frame2
+// CHECK0: #3{{.*}}Frame3
+// CHECK0: is located in stack of thread T0 at offset
+// CHECK0-NEXT: #0{{.*}}Frame0
+//
+// CHECK1: AddressSanitizer: stack-buffer-overflow
+// CHECK1: is located in stack of thread T0 at offset
+// CHECK1-NEXT: #0{{.*}}Frame1
+//
+// CHECK2: AddressSanitizer: stack-buffer-overflow
+// CHECK2: is located in stack of thread T0 at offset
+// CHECK2-NEXT: #0{{.*}}Frame2
+//
+// CHECK3: AddressSanitizer: stack-buffer-overflow
+// CHECK3: is located in stack of thread T0 at offset
+// CHECK3-NEXT: #0{{.*}}Frame3
diff --git a/test/asan/TestCases/stack-overflow.cc b/test/asan/TestCases/stack-overflow.cc
new file mode 100644
index 000000000000..7542d56b6db8
--- /dev/null
+++ b/test/asan/TestCases/stack-overflow.cc
@@ -0,0 +1,114 @@
+// Test ASan detection of stack-overflow condition.
+
+// RUN: %clangxx_asan -O0 %s -DSMALL_FRAME -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -DSMALL_FRAME -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O0 %s -DSAVE_ALL_THE_REGISTERS -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -DSAVE_ALL_THE_REGISTERS -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O0 %s -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
+
+// RUN: %clangxx_asan -O0 %s -DTHREAD -DSMALL_FRAME -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -DTHREAD -DSMALL_FRAME -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O0 %s -DTHREAD -DSAVE_ALL_THE_REGISTERS -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -DTHREAD -DSAVE_ALL_THE_REGISTERS -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O0 %s -DTHREAD -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -DTHREAD -pthread -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s
+// RUN: not %run %t 2>&1 | FileCheck %s
+// REQUIRES: stable-runtime
+
+#include <assert.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sanitizer/asan_interface.h>
+
+const int BS = 1024;
+volatile char x;
+volatile int y = 1;
+volatile int z0, z1, z2, z3, z4, z5, z6, z7, z8, z9, z10, z11, z12, z13;
+
+void recursive_func(char *p) {
+#if defined(SMALL_FRAME)
+ char *buf = 0;
+#elif defined(SAVE_ALL_THE_REGISTERS)
+ char *buf = 0;
+ int t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13;
+ t0 = z0;
+ t1 = z1;
+ t2 = z2;
+ t3 = z3;
+ t4 = z4;
+ t5 = z5;
+ t6 = z6;
+ t7 = z7;
+ t8 = z8;
+ t9 = z9;
+ t10 = z10;
+ t11 = z11;
+ t12 = z12;
+ t13 = z13;
+
+ z0 = t0;
+ z1 = t1;
+ z2 = t2;
+ z3 = t3;
+ z4 = t4;
+ z5 = t5;
+ z6 = t6;
+ z7 = t7;
+ z8 = t8;
+ z9 = t9;
+ z10 = t10;
+ z11 = t11;
+ z12 = t12;
+ z13 = t13;
+#else
+ char buf[BS];
+ // Check that the stack grows in the righ direction, unless we use fake stack.
+ if (p && !__asan_get_current_fake_stack())
+ assert(p - buf >= BS);
+ buf[rand() % BS] = 1;
+ buf[rand() % BS] = 2;
+ x = buf[rand() % BS];
+#endif
+ if (y)
+ recursive_func(buf);
+ x = 1; // prevent tail call optimization
+ // CHECK: {{stack-overflow on address 0x.* \(pc 0x.* bp 0x.* sp 0x.* T.*\)}}
+ // If stack overflow happens during function prologue, stack trace may be
+ // corrupted. Unwind tables are not always 100% exact there.
+ // For this reason, we don't do any further checks.
+}
+
+void *ThreadFn(void* unused) {
+ recursive_func(0);
+ return 0;
+}
+
+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 = 128 * 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);
+#ifdef THREAD
+ pthread_t t;
+ pthread_create(&t, 0, ThreadFn, 0);
+ pthread_join(t, 0);
+#else
+ recursive_func(0);
+#endif
+ return 0;
+}
diff --git a/test/asan/TestCases/stack-use-after-return.cc b/test/asan/TestCases/stack-use-after-return.cc
new file mode 100644
index 000000000000..437c457748c4
--- /dev/null
+++ b/test/asan/TestCases/stack-use-after-return.cc
@@ -0,0 +1,80 @@
+// RUN: export ASAN_OPTIONS=detect_stack_use_after_return=1
+// RUN: %clangxx_asan -O0 %s -pthread -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -pthread -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -pthread -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -pthread -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: env ASAN_OPTIONS=detect_stack_use_after_return=0 %run %t
+// Regression test for a CHECK failure with small stack size and large frame.
+// RUN: %clangxx_asan -O3 %s -pthread -o %t -DkSize=10000 -DUseThread -DkStackSize=65536 && not %run %t 2>&1 | FileCheck --check-prefix=THREAD %s
+//
+// Test that we can find UAR in a thread other than main:
+// RUN: %clangxx_asan -DUseThread -O2 %s -pthread -o %t && not %run %t 2>&1 | FileCheck --check-prefix=THREAD %s
+//
+// Test the max_uar_stack_size_log/min_uar_stack_size_log flag.
+//
+// RUN: env ASAN_OPTIONS=$ASAN_OPTIONS:max_uar_stack_size_log=20:verbosity=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-20 %s
+// RUN: env ASAN_OPTIONS=$ASAN_OPTIONS:min_uar_stack_size_log=24:max_uar_stack_size_log=24:verbosity=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-24 %s
+
+#include <stdio.h>
+#include <pthread.h>
+
+#ifndef kSize
+# define kSize 1
+#endif
+
+#ifndef UseThread
+# define UseThread 0
+#endif
+
+#ifndef kStackSize
+# define kStackSize 0
+#endif
+
+__attribute__((noinline))
+char *Ident(char *x) {
+ fprintf(stderr, "1: %p\n", x);
+ return x;
+}
+
+__attribute__((noinline))
+char *Func1() {
+ char local[kSize];
+ return Ident(local);
+}
+
+__attribute__((noinline))
+void Func2(char *x) {
+ fprintf(stderr, "2: %p\n", x);
+ *x = 1;
+ // CHECK: WRITE of size 1 {{.*}} thread T0
+ // CHECK: #0{{.*}}Func2{{.*}}stack-use-after-return.cc:[[@LINE-2]]
+ // CHECK: is located in stack of thread T0 at offset
+ // CHECK: 'local' <== Memory access at offset {{16|32}} is inside this variable
+ // THREAD: WRITE of size 1 {{.*}} thread T{{[1-9]}}
+ // THREAD: #0{{.*}}Func2{{.*}}stack-use-after-return.cc:[[@LINE-6]]
+ // THREAD: is located in stack of thread T{{[1-9]}} at offset
+ // THREAD: 'local' <== Memory access at offset {{16|32}} is inside this variable
+ // CHECK-20: T0: FakeStack created:{{.*}} stack_size_log: 20
+ // CHECK-24: T0: FakeStack created:{{.*}} stack_size_log: 24
+}
+
+void *Thread(void *unused) {
+ Func2(Func1());
+ return NULL;
+}
+
+int main(int argc, char **argv) {
+#if UseThread
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ if (kStackSize > 0)
+ pthread_attr_setstacksize(&attr, kStackSize);
+ pthread_t t;
+ pthread_create(&t, &attr, Thread, 0);
+ pthread_attr_destroy(&attr);
+ pthread_join(t, 0);
+#else
+ Func2(Func1());
+#endif
+ return 0;
+}
diff --git a/test/asan/TestCases/strdup_oob_test.cc b/test/asan/TestCases/strdup_oob_test.cc
new file mode 100644
index 000000000000..a039568b2245
--- /dev/null
+++ b/test/asan/TestCases/strdup_oob_test.cc
@@ -0,0 +1,20 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// 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
+
+#include <string.h>
+
+char kString[] = "foo";
+
+int main(int argc, char **argv) {
+ char *copy = strdup(kString);
+ int x = copy[4 + argc]; // BOOM
+ // CHECK: AddressSanitizer: heap-buffer-overflow
+ // CHECK: #0 {{.*}}main {{.*}}strdup_oob_test.cc:[[@LINE-2]]
+ // CHECK-LABEL: allocated by thread T{{.*}} here:
+ // CHECK: #{{[01]}} {{.*}}strdup
+ // CHECK-LABEL: SUMMARY
+ // CHECK: strdup_oob_test.cc:[[@LINE-6]]
+ return x;
+}
diff --git a/test/asan/TestCases/strip_path_prefix.c b/test/asan/TestCases/strip_path_prefix.c
new file mode 100644
index 000000000000..4556e9031e2d
--- /dev/null
+++ b/test/asan/TestCases/strip_path_prefix.c
@@ -0,0 +1,12 @@
+// RUN: %clang_asan -O2 %s -o %t
+// RUN: env ASAN_OPTIONS="strip_path_prefix='/'" not %run %t 2>&1 | FileCheck %s
+
+#include <stdlib.h>
+int main() {
+ char *x = (char*)malloc(10 * sizeof(char));
+ free(x);
+ return x[5];
+ // Check that paths in error report don't start with slash.
+ // CHECK: heap-use-after-free
+ // CHECK-NOT: #0 0x{{.*}} ({{[/].*}})
+}
diff --git a/test/asan/TestCases/strncpy-overflow.cc b/test/asan/TestCases/strncpy-overflow.cc
new file mode 100644
index 000000000000..651ae22795f1
--- /dev/null
+++ b/test/asan/TestCases/strncpy-overflow.cc
@@ -0,0 +1,30 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
+// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
+// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
+// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
+
+// REQUIRES: compiler-rt-optimized
+// XFAIL: arm-linux-gnueabi
+// XFAIL: armv7l-unknown-linux-gnueabihf
+
+#include <string.h>
+#include <stdlib.h>
+int main(int argc, char **argv) {
+ char *hello = (char*)malloc(6);
+ strcpy(hello, "hello");
+ char *short_buffer = (char*)malloc(9);
+ strncpy(short_buffer, hello, 10); // BOOM
+ // CHECK: {{WRITE of size 10 at 0x.* thread T0}}
+ // CHECK-Linux: {{ #0 0x.* in .*strncpy}}
+ // CHECK-Darwin: {{ #0 0x.* in wrap_strncpy}}
+ // CHECK: {{ #1 0x.* in main .*strncpy-overflow.cc:}}[[@LINE-4]]
+ // CHECK: {{0x.* is located 0 bytes to the right of 9-byte region}}
+ // CHECK: {{allocated by thread T0 here:}}
+
+ // CHECK-Linux: {{ #0 0x.* in .*malloc}}
+ // CHECK-Linux: {{ #1 0x.* in main .*strncpy-overflow.cc:}}[[@LINE-10]]
+
+ // CHECK-Darwin: {{ #0 0x.* in wrap_malloc.*}}
+ // CHECK-Darwin: {{ #1 0x.* in main .*strncpy-overflow.cc:}}[[@LINE-13]]
+ return short_buffer[8];
+}
diff --git a/test/asan/TestCases/suppressions-function.cc b/test/asan/TestCases/suppressions-function.cc
new file mode 100644
index 000000000000..c52b3c303518
--- /dev/null
+++ b/test/asan/TestCases/suppressions-function.cc
@@ -0,0 +1,29 @@
+// Check that without suppressions, we catch the issue.
+// RUN: %clangxx_asan -O0 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck --check-prefix=CHECK-CRASH %s
+
+// RUN: echo "interceptor_via_fun:crash_function" > %t.supp
+// RUN: %clangxx_asan -O0 %s -o %t && ASAN_OPTIONS=suppressions=%t.supp %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s
+// RUN: %clangxx_asan -O3 %s -o %t && ASAN_OPTIONS=suppressions=%t.supp %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s
+
+// XFAIL: android
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void crash_function() {
+ char *a = (char *)malloc(6);
+ free(a);
+ size_t len = strlen(a); // BOOM
+ fprintf(stderr, "strlen ignored, len = %zu\n", len);
+}
+
+int main() {
+ crash_function();
+}
+
+// CHECK-CRASH: AddressSanitizer: heap-use-after-free
+// CHECK-CRASH-NOT: strlen ignored
+// CHECK-IGNORE-NOT: AddressSanitizer: heap-use-after-free
+// CHECK-IGNORE: strlen ignored
diff --git a/test/asan/TestCases/suppressions-interceptor.cc b/test/asan/TestCases/suppressions-interceptor.cc
new file mode 100644
index 000000000000..10d24fdc30a3
--- /dev/null
+++ b/test/asan/TestCases/suppressions-interceptor.cc
@@ -0,0 +1,24 @@
+// Check that without suppressions, we catch the issue.
+// RUN: %clangxx_asan -O0 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck --check-prefix=CHECK-CRASH %s
+
+// RUN: echo "interceptor_name:strlen" > %t.supp
+// RUN: ASAN_OPTIONS=suppressions=%t.supp %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s
+
+// XFAIL: android
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main() {
+ char *a = (char *)malloc(6);
+ free(a);
+ size_t len = strlen(a); // BOOM
+ fprintf(stderr, "strlen ignored, len = %zu\n", len);
+}
+
+// CHECK-CRASH: AddressSanitizer: heap-use-after-free
+// CHECK-CRASH-NOT: strlen ignored
+// CHECK-IGNORE-NOT: AddressSanitizer: heap-use-after-free
+// CHECK-IGNORE: strlen ignored
diff --git a/test/asan/TestCases/suppressions-library.cc b/test/asan/TestCases/suppressions-library.cc
new file mode 100644
index 000000000000..dfb0d4a5e030
--- /dev/null
+++ b/test/asan/TestCases/suppressions-library.cc
@@ -0,0 +1,39 @@
+// RUN: %clangxx_asan -O0 -DSHARED_LIB %s -fPIC -shared -o %t-so.so
+// RUN: %clangxx_asan -O0 %s %t-so.so -o %t
+
+// Check that without suppressions, we catch the issue.
+// RUN: not %run %t 2>&1 | FileCheck --check-prefix=CHECK-CRASH %s
+
+// RUN: echo "interceptor_via_lib:%t-so.so" > %t.supp
+// RUN: ASAN_OPTIONS=suppressions=%t.supp %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s
+
+// XFAIL: android
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if !defined(SHARED_LIB)
+
+void crash_function();
+
+int main(int argc, char *argv[]) {
+ crash_function();
+ return 0;
+}
+
+#else // SHARED_LIB
+
+void crash_function() {
+ char *a = (char *)malloc(6);
+ free(a);
+ size_t len = strlen(a); // BOOM
+ fprintf(stderr, "strlen ignored, %zu\n", len);
+}
+
+#endif // SHARED_LIB
+
+// CHECK-CRASH: AddressSanitizer: heap-use-after-free
+// CHECK-CRASH-NOT: strlen ignored
+// CHECK-IGNORE-NOT: AddressSanitizer: heap-use-after-free
+// CHECK-IGNORE: strlen ignored
diff --git a/test/asan/TestCases/throw_call_test.cc b/test/asan/TestCases/throw_call_test.cc
new file mode 100644
index 000000000000..20e9a5ee565e
--- /dev/null
+++ b/test/asan/TestCases/throw_call_test.cc
@@ -0,0 +1,52 @@
+// RUN: %clangxx_asan %s -o %t && %run %t
+// http://code.google.com/p/address-sanitizer/issues/detail?id=147 (not fixed).
+// BROKEN: %clangxx_asan %s -o %t -static-libstdc++ && %run %t
+//
+// 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) {
+ __asm__ __volatile__("" : : "r" (x) : "memory");
+}
+
+__attribute__((noinline, no_sanitize_address))
+void ReallyThrow() {
+ fprintf(stderr, "ReallyThrow\n");
+ if (zero == 0)
+ throw 42;
+}
+
+__attribute__((noinline))
+void Throw() {
+ int a, b, c, d, e;
+ pretend_to_do_something(&a);
+ pretend_to_do_something(&b);
+ pretend_to_do_something(&c);
+ pretend_to_do_something(&d);
+ pretend_to_do_something(&e);
+ fprintf(stderr, "Throw stack = %p\n", &a);
+ ReallyThrow();
+}
+
+__attribute__((noinline))
+void CheckStack() {
+ int ar[100];
+ pretend_to_do_something(ar);
+ for (int i = 0; i < 100; i++)
+ ar[i] = i;
+ fprintf(stderr, "CheckStack stack = %p, %p\n", ar, ar + 100);
+}
+
+int main(int argc, char** argv) {
+ try {
+ Throw();
+ } catch(int a) {
+ fprintf(stderr, "a = %d\n", a);
+ }
+ CheckStack();
+}
diff --git a/test/asan/TestCases/throw_catch.cc b/test/asan/TestCases/throw_catch.cc
new file mode 100644
index 000000000000..bce48199dbf7
--- /dev/null
+++ b/test/asan/TestCases/throw_catch.cc
@@ -0,0 +1,64 @@
+// RUN: %clangxx_asan -O %s -o %t && %run %t
+
+// Clang doesn't support exceptions on Windows yet.
+// XFAIL: win32
+
+#include <assert.h>
+#include <stdio.h>
+#include <sanitizer/asan_interface.h>
+
+__attribute__((noinline))
+void Throw() {
+ int local;
+ fprintf(stderr, "Throw: %p\n", &local);
+ throw 1;
+}
+
+__attribute__((noinline))
+void ThrowAndCatch() {
+ int local;
+ try {
+ Throw();
+ } catch(...) {
+ fprintf(stderr, "Catch: %p\n", &local);
+ }
+}
+
+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
+ // This assertion works only w/o UAR.
+ if (!__asan_get_current_fake_stack())
+ assert(!__asan_address_is_poisoned(x + 32));
+}
+
+void TestThrowInline() {
+ char x[32];
+ fprintf(stderr, "Before: %p poisoned: %d\n", &x,
+ __asan_address_is_poisoned(x + 32));
+ assert(__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
+ // This assertion works only w/o UAR.
+ if (!__asan_get_current_fake_stack())
+ assert(!__asan_address_is_poisoned(x + 32));
+}
+
+int main(int argc, char **argv) {
+ TestThrowInline();
+ TestThrow();
+}
diff --git a/test/asan/TestCases/throw_invoke_test.cc b/test/asan/TestCases/throw_invoke_test.cc
new file mode 100644
index 000000000000..ec48fc7b6a49
--- /dev/null
+++ b/test/asan/TestCases/throw_invoke_test.cc
@@ -0,0 +1,54 @@
+// 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
+
+#include <stdio.h>
+static volatile int zero = 0;
+inline void pretend_to_do_something(void *x) {
+ __asm__ __volatile__("" : : "r" (x) : "memory");
+}
+
+__attribute__((noinline))
+void ReallyThrow() {
+ fprintf(stderr, "ReallyThrow\n");
+ try {
+ if (zero == 0)
+ throw 42;
+ else if (zero == 1)
+ throw 1.;
+ } catch(double x) {
+ }
+}
+
+__attribute__((noinline))
+void Throw() {
+ int a, b, c, d, e;
+ pretend_to_do_something(&a);
+ pretend_to_do_something(&b);
+ pretend_to_do_something(&c);
+ pretend_to_do_something(&d);
+ pretend_to_do_something(&e);
+ fprintf(stderr, "Throw stack = %p\n", &a);
+ ReallyThrow();
+}
+
+__attribute__((noinline))
+void CheckStack() {
+ int ar[100];
+ pretend_to_do_something(ar);
+ for (int i = 0; i < 100; i++)
+ ar[i] = i;
+ fprintf(stderr, "CheckStack stack = %p, %p\n", ar, ar + 100);
+}
+
+int main(int argc, char** argv) {
+ try {
+ Throw();
+ } catch(int a) {
+ fprintf(stderr, "a = %d\n", a);
+ }
+ CheckStack();
+}
+
diff --git a/test/asan/TestCases/time_interceptor.cc b/test/asan/TestCases/time_interceptor.cc
new file mode 100644
index 000000000000..89b2183bcde2
--- /dev/null
+++ b/test/asan/TestCases/time_interceptor.cc
@@ -0,0 +1,22 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+// Test the time() interceptor.
+
+// There's no interceptor for time() on Windows yet.
+// XFAIL: win32
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+int main() {
+ time_t *tm = (time_t*)malloc(sizeof(time_t));
+ free(tm);
+ time_t t = time(tm);
+ printf("Time: %s\n", ctime(&t)); // NOLINT
+ // CHECK: use-after-free
+ // Regression check for
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=321
+ // CHECK: SUMMARY
+ return 0;
+}
diff --git a/test/asan/TestCases/uar_and_exceptions.cc b/test/asan/TestCases/uar_and_exceptions.cc
new file mode 100644
index 000000000000..0bfe29729555
--- /dev/null
+++ b/test/asan/TestCases/uar_and_exceptions.cc
@@ -0,0 +1,43 @@
+// Test that use-after-return works with exceptions.
+// export ASAN_OPTIONS=detect_stack_use_after_return=1
+// RUN: %clangxx_asan -O0 %s -o %t && %run %t
+
+// Clang doesn't support exceptions on Windows yet.
+// XFAIL: win32
+
+#include <stdio.h>
+
+volatile char *g;
+
+#ifndef FRAME_SIZE
+# define FRAME_SIZE 100
+#endif
+
+#ifndef NUM_ITER
+# define NUM_ITER 4000
+#endif
+
+#ifndef DO_THROW
+# define DO_THROW 1
+#endif
+
+void Func(int depth) {
+ char frame[FRAME_SIZE];
+ g = &frame[0];
+ if (depth)
+ Func(depth - 1);
+ else if (DO_THROW)
+ throw 1;
+}
+
+int main(int argc, char **argv) {
+ for (int i = 0; i < NUM_ITER; i++) {
+ try {
+ Func(argc * 100);
+ } catch(...) {
+ }
+ if ((i % (NUM_ITER / 10)) == 0)
+ fprintf(stderr, "done [%d]\n", i);
+ }
+ return 0;
+}
diff --git a/test/asan/TestCases/unaligned_loads_and_stores.cc b/test/asan/TestCases/unaligned_loads_and_stores.cc
new file mode 100644
index 000000000000..f1b1d0d457e1
--- /dev/null
+++ b/test/asan/TestCases/unaligned_loads_and_stores.cc
@@ -0,0 +1,52 @@
+// RUN: %clangxx_asan -O0 %s -o %t
+// RUN: not %run %t A 2>&1 | FileCheck --check-prefix=CHECK-A %s
+// RUN: not %run %t B 2>&1 | FileCheck --check-prefix=CHECK-B %s
+// RUN: not %run %t C 2>&1 | FileCheck --check-prefix=CHECK-C %s
+// RUN: not %run %t D 2>&1 | FileCheck --check-prefix=CHECK-D %s
+// RUN: not %run %t E 2>&1 | FileCheck --check-prefix=CHECK-E %s
+
+// RUN: not %run %t K 2>&1 | FileCheck --check-prefix=CHECK-K %s
+// RUN: not %run %t L 2>&1 | FileCheck --check-prefix=CHECK-L %s
+// RUN: not %run %t M 2>&1 | FileCheck --check-prefix=CHECK-M %s
+// RUN: not %run %t N 2>&1 | FileCheck --check-prefix=CHECK-N %s
+// RUN: not %run %t O 2>&1 | FileCheck --check-prefix=CHECK-O %s
+
+#include <sanitizer/asan_interface.h>
+
+#include <stdlib.h>
+#include <string.h>
+int main(int argc, char **argv) {
+ if (argc != 2) return 1;
+ char *x = new char[16];
+ memset(x, 0xab, 16);
+ int res = 1;
+ switch (argv[1][0]) {
+ case 'A': res = __sanitizer_unaligned_load16(x + 15); break;
+// CHECK-A ERROR: AddressSanitizer: heap-buffer-overflow on address
+// CHECK-A: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-2]]
+// CHECK-A: is located 0 bytes to the right of 16-byte region
+ case 'B': res = __sanitizer_unaligned_load32(x + 14); break;
+// CHECK-B: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
+ case 'C': res = __sanitizer_unaligned_load32(x + 13); break;
+// CHECK-C: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
+ case 'D': res = __sanitizer_unaligned_load64(x + 15); break;
+// CHECK-D: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
+ case 'E': res = __sanitizer_unaligned_load64(x + 9); break;
+// CHECK-E: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
+
+ case 'K': __sanitizer_unaligned_store16(x + 15, 0); break;
+// CHECK-K ERROR: AddressSanitizer: heap-buffer-overflow on address
+// CHECK-K: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-2]]
+// CHECK-K: is located 0 bytes to the right of 16-byte region
+ case 'L': __sanitizer_unaligned_store32(x + 15, 0); break;
+// CHECK-L: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
+ case 'M': __sanitizer_unaligned_store32(x + 13, 0); break;
+// CHECK-M: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
+ case 'N': __sanitizer_unaligned_store64(x + 10, 0); break;
+// CHECK-N: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
+ case 'O': __sanitizer_unaligned_store64(x + 14, 0); break;
+// CHECK-O: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]]
+ }
+ delete x;
+ return res;
+}
diff --git a/test/asan/TestCases/use-after-delete.cc b/test/asan/TestCases/use-after-delete.cc
new file mode 100644
index 000000000000..8fdec8d83c80
--- /dev/null
+++ b/test/asan/TestCases/use-after-delete.cc
@@ -0,0 +1,31 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
+// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
+// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
+// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
+// XFAIL: arm-linux-gnueabi
+// XFAIL: armv7l-unknown-linux-gnueabihf
+
+#include <stdlib.h>
+int main() {
+ char * volatile x = new char[10];
+ delete[] x;
+ return x[5];
+ // CHECK: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}}
+ // CHECK: {{0x.* at pc 0x.* bp 0x.* sp 0x.*}}
+ // CHECK: {{READ of size 1 at 0x.* thread T0}}
+ // CHECK: {{ #0 0x.* in main .*use-after-delete.cc:}}[[@LINE-4]]
+ // CHECK: {{0x.* is located 5 bytes inside of 10-byte region .0x.*,0x.*}}
+ // CHECK: {{freed by thread T0 here:}}
+
+ // CHECK-Linux: {{ #0 0x.* in operator delete\[\]}}
+ // CHECK-Linux: {{ #1 0x.* in main .*use-after-delete.cc:}}[[@LINE-10]]
+
+ // CHECK: {{previously allocated by thread T0 here:}}
+
+ // CHECK-Linux: {{ #0 0x.* in operator new\[\]}}
+ // CHECK-Linux: {{ #1 0x.* in main .*use-after-delete.cc:}}[[@LINE-16]]
+
+ // CHECK: Shadow byte legend (one shadow byte represents 8 application bytes):
+ // CHECK: Global redzone:
+ // CHECK: ASan internal:
+}
diff --git a/test/asan/TestCases/use-after-free-right.cc b/test/asan/TestCases/use-after-free-right.cc
new file mode 100644
index 000000000000..f714b44f2f1f
--- /dev/null
+++ b/test/asan/TestCases/use-after-free-right.cc
@@ -0,0 +1,36 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
+// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
+// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
+// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
+// XFAIL: arm-linux-gnueabi
+// XFAIL: armv7l-unknown-linux-gnueabihf
+
+// Test use-after-free report in the case when access is at the right border of
+// the allocation.
+
+#include <stdlib.h>
+int main() {
+ volatile char *x = (char*)malloc(sizeof(char));
+ free((void*)x);
+ *x = 42;
+ // CHECK: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}}
+ // CHECK: {{0x.* at pc 0x.* bp 0x.* sp 0x.*}}
+ // CHECK: {{WRITE of size 1 at 0x.* thread T0}}
+ // CHECK: {{ #0 0x.* in main .*use-after-free-right.cc:}}[[@LINE-4]]
+ // CHECK: {{0x.* is located 0 bytes inside of 1-byte region .0x.*,0x.*}}
+ // CHECK: {{freed by thread T0 here:}}
+
+ // CHECK-Linux: {{ #0 0x.* in .*free}}
+ // CHECK-Linux: {{ #1 0x.* in main .*use-after-free-right.cc:}}[[@LINE-10]]
+
+ // CHECK-Darwin: {{ #0 0x.* in wrap_free}}
+ // CHECK-Darwin: {{ #1 0x.* in main .*use-after-free-right.cc:}}[[@LINE-13]]
+
+ // CHECK: {{previously allocated by thread T0 here:}}
+
+ // CHECK-Linux: {{ #0 0x.* in .*malloc}}
+ // CHECK-Linux: {{ #1 0x.* in main .*use-after-free-right.cc:}}[[@LINE-19]]
+
+ // CHECK-Darwin: {{ #0 0x.* in wrap_malloc.*}}
+ // CHECK-Darwin: {{ #1 0x.* in main .*use-after-free-right.cc:}}[[@LINE-22]]
+}
diff --git a/test/asan/TestCases/use-after-free.cc b/test/asan/TestCases/use-after-free.cc
new file mode 100644
index 000000000000..7bc225b1ef86
--- /dev/null
+++ b/test/asan/TestCases/use-after-free.cc
@@ -0,0 +1,36 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
+// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
+// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
+// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
+// XFAIL: arm-linux-gnueabi
+// XFAIL: armv7l-unknown-linux-gnueabihf
+
+#include <stdlib.h>
+int main() {
+ char *x = (char*)malloc(10 * sizeof(char));
+ free(x);
+ return x[5];
+ // CHECK: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}}
+ // CHECK: {{0x.* at pc 0x.* bp 0x.* sp 0x.*}}
+ // CHECK: {{READ of size 1 at 0x.* thread T0}}
+ // CHECK: {{ #0 0x.* in main .*use-after-free.cc:}}[[@LINE-4]]
+ // CHECK: {{0x.* is located 5 bytes inside of 10-byte region .0x.*,0x.*}}
+ // CHECK: {{freed by thread T0 here:}}
+
+ // CHECK-Linux: {{ #0 0x.* in .*free}}
+ // CHECK-Linux: {{ #1 0x.* in main .*use-after-free.cc:}}[[@LINE-10]]
+
+ // CHECK-Darwin: {{ #0 0x.* in wrap_free}}
+ // CHECK-Darwin: {{ #1 0x.* in main .*use-after-free.cc:}}[[@LINE-13]]
+
+ // CHECK: {{previously allocated by thread T0 here:}}
+
+ // CHECK-Linux: {{ #0 0x.* in .*malloc}}
+ // CHECK-Linux: {{ #1 0x.* in main .*use-after-free.cc:}}[[@LINE-19]]
+
+ // CHECK-Darwin: {{ #0 0x.* in wrap_malloc.*}}
+ // CHECK-Darwin: {{ #1 0x.* in main .*use-after-free.cc:}}[[@LINE-22]]
+ // CHECK: Shadow byte legend (one shadow byte represents 8 application bytes):
+ // CHECK: Global redzone:
+ // CHECK: ASan internal:
+}
diff --git a/test/asan/TestCases/use-after-poison.cc b/test/asan/TestCases/use-after-poison.cc
new file mode 100644
index 000000000000..3b247ff531b9
--- /dev/null
+++ b/test/asan/TestCases/use-after-poison.cc
@@ -0,0 +1,20 @@
+// Check that __asan_poison_memory_region works.
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+//
+// Check that we can disable it
+// RUN: env ASAN_OPTIONS=allow_user_poisoning=0 %run %t
+
+#include <stdlib.h>
+
+extern "C" void __asan_poison_memory_region(void *, size_t);
+
+int main(int argc, char **argv) {
+ char *x = new char[16];
+ x[10] = 0;
+ __asan_poison_memory_region(x, 16);
+ int res = x[argc * 10]; // BOOOM
+ // CHECK: ERROR: AddressSanitizer: use-after-poison
+ // CHECK: main{{.*}}use-after-poison.cc:[[@LINE-2]]
+ delete [] x;
+ return res;
+}
diff --git a/test/asan/TestCases/use-after-scope-dtor-order.cc b/test/asan/TestCases/use-after-scope-dtor-order.cc
new file mode 100644
index 000000000000..7896dd30c400
--- /dev/null
+++ b/test/asan/TestCases/use-after-scope-dtor-order.cc
@@ -0,0 +1,26 @@
+// RUN: %clangxx_asan -O0 -fsanitize=use-after-scope %s -o %t && \
+// RUN: not %run %t 2>&1 | FileCheck %s
+// XFAIL: *
+#include <stdio.h>
+
+struct IntHolder {
+ explicit IntHolder(int *val = 0) : val_(val) { }
+ ~IntHolder() {
+ printf("Value: %d\n", *val_); // BOOM
+ // CHECK: ERROR: AddressSanitizer: stack-use-after-scope
+ // CHECK: #0 0x{{.*}} in IntHolder::~IntHolder{{.*}}use-after-scope-dtor-order.cc:[[@LINE-2]]
+ }
+ void set(int *val) { val_ = val; }
+ int *get() { return val_; }
+
+ int *val_;
+};
+
+int main(int argc, char *argv[]) {
+ // It is incorrect to use "x" int IntHolder destructor, because "x" is
+ // "destroyed" earlier as it's declared later.
+ IntHolder holder;
+ int x = argc;
+ holder.set(&x);
+ return 0;
+}
diff --git a/test/asan/TestCases/use-after-scope-inlined.cc b/test/asan/TestCases/use-after-scope-inlined.cc
new file mode 100644
index 000000000000..a0a0d9461cb9
--- /dev/null
+++ b/test/asan/TestCases/use-after-scope-inlined.cc
@@ -0,0 +1,28 @@
+// Test with "-O2" only to make sure inlining (leading to use-after-scope)
+// happens. "always_inline" is not enough, as Clang doesn't emit
+// llvm.lifetime intrinsics at -O0.
+//
+// RUN: %clangxx_asan -O2 -fsanitize=use-after-scope %s -o %t && not %run %t 2>&1 | FileCheck %s
+// XFAIL: *
+
+int *arr;
+
+__attribute__((always_inline))
+void inlined(int arg) {
+ int x[5];
+ for (int i = 0; i < arg; i++) x[i] = i;
+ arr = x;
+}
+
+int main(int argc, char *argv[]) {
+ inlined(argc);
+ return arr[argc - 1]; // BOOM
+ // CHECK: ERROR: AddressSanitizer: stack-use-after-scope
+ // CHECK: READ of size 4 at 0x{{.*}} thread T0
+ // CHECK: #0 0x{{.*}} in main
+ // CHECK: {{.*}}use-after-scope-inlined.cc:[[@LINE-4]]
+ // CHECK: Address 0x{{.*}} is located in stack of thread T0 at offset
+ // CHECK: [[OFFSET:[^ ]*]] in frame
+ // CHECK: main
+ // CHECK: {{\[}}[[OFFSET]], {{.*}}) 'x.i'
+}
diff --git a/test/asan/TestCases/use-after-scope-nobug.cc b/test/asan/TestCases/use-after-scope-nobug.cc
new file mode 100644
index 000000000000..21b085c96275
--- /dev/null
+++ b/test/asan/TestCases/use-after-scope-nobug.cc
@@ -0,0 +1,15 @@
+// RUN: %clangxx_asan -O0 -fsanitize=use-after-scope %s -o %t && %run %t
+// XFAIL: *
+
+#include <stdio.h>
+
+int main() {
+ int *p = 0;
+ // Variable goes in and out of scope.
+ for (int i = 0; i < 3; i++) {
+ int x = 0;
+ p = &x;
+ }
+ printf("PASSED\n");
+ return 0;
+}
diff --git a/test/asan/TestCases/use-after-scope-temp.cc b/test/asan/TestCases/use-after-scope-temp.cc
new file mode 100644
index 000000000000..f9bd779ac1a2
--- /dev/null
+++ b/test/asan/TestCases/use-after-scope-temp.cc
@@ -0,0 +1,29 @@
+// RUN: %clangxx_asan -O0 -fsanitize=use-after-scope %s -o %t && \
+// RUN: %run %t 2>&1 | FileCheck %s
+//
+// Lifetime for temporaries is not emitted yet.
+// XFAIL: *
+
+#include <stdio.h>
+
+struct IntHolder {
+ explicit IntHolder(int val) : val(val) {
+ printf("IntHolder: %d\n", val);
+ }
+ int val;
+};
+
+const IntHolder *saved;
+
+void save(const IntHolder &holder) {
+ saved = &holder;
+}
+
+int main(int argc, char *argv[]) {
+ save(IntHolder(10));
+ int x = saved->val; // BOOM
+ // CHECK: ERROR: AddressSanitizer: stack-use-after-scope
+ // CHECK: #0 0x{{.*}} in main {{.*}}use-after-scope-temp.cc:[[@LINE-2]]
+ printf("saved value: %d\n", x);
+ return 0;
+}
diff --git a/test/asan/TestCases/use-after-scope.cc b/test/asan/TestCases/use-after-scope.cc
new file mode 100644
index 000000000000..f98a8e6b62e1
--- /dev/null
+++ b/test/asan/TestCases/use-after-scope.cc
@@ -0,0 +1,17 @@
+// RUN: %clangxx_asan -O0 -fsanitize=use-after-scope %s -o %t && \
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: env ASAN_OPTIONS="detect_stack_use_after_return=1" not %run %t 2>&1 | FileCheck %s
+// XFAIL: *
+
+int main() {
+ int *p = 0;
+ {
+ int x = 0;
+ p = &x;
+ }
+ return *p; // BOOM
+ // CHECK: ERROR: AddressSanitizer: stack-use-after-scope
+ // CHECK: #0 0x{{.*}} in main {{.*}}use-after-scope.cc:[[@LINE-2]]
+ // CHECK: Address 0x{{.*}} is located in stack of thread T{{.*}} at offset [[OFFSET:[^ ]+]] in frame
+ // {{\[}}[[OFFSET]], {{[0-9]+}}) 'x'
+}
diff --git a/test/asan/TestCases/zero_page_pc.cc b/test/asan/TestCases/zero_page_pc.cc
new file mode 100644
index 000000000000..5810a9fb9dde
--- /dev/null
+++ b/test/asan/TestCases/zero_page_pc.cc
@@ -0,0 +1,12 @@
+// Check that ASan correctly detects SEGV on the zero page.
+// RUN: %clangxx_asan %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+typedef void void_f();
+int main() {
+ void_f *func = (void_f *)0x4;
+ func();
+ // x86 reports the SEGV with both address=4 and pc=4.
+ // PowerPC64 reports it with address=4 but pc still in main().
+ // CHECK: {{AddressSanitizer: SEGV.*(address|pc) 0x0*4}}
+ return 0;
+}
diff --git a/test/asan/Unit/lit.site.cfg.in b/test/asan/Unit/lit.site.cfg.in
new file mode 100644
index 000000000000..1791b6b05b1c
--- /dev/null
+++ b/test/asan/Unit/lit.site.cfg.in
@@ -0,0 +1,24 @@
+## Autogenerated by LLVM/Clang configuration.
+# Do not edit!
+
+import os
+
+# Load common config for all compiler-rt unit tests.
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/unittests/lit.common.unit.configured")
+
+def push_ld_library_path(config, new_path):
+ new_ld_library_path = os.path.pathsep.join(
+ (new_path, config.environment['LD_LIBRARY_PATH']))
+ config.environment['LD_LIBRARY_PATH'] = new_ld_library_path
+
+# Setup config name.
+config.name = 'AddressSanitizer-Unit'
+
+# Setup test source and exec root. For unit tests, we define
+# it as build directory with ASan unit tests.
+# FIXME: De-hardcode this path.
+config.test_exec_root = "@COMPILER_RT_BINARY_DIR@/lib/asan/tests"
+config.test_source_root = config.test_exec_root
+
+# Set LD_LIBRARY_PATH to pick dynamic runtime up properly.
+push_ld_library_path(config, config.compiler_rt_libdir)
diff --git a/test/asan/android_commands/android_common.py b/test/asan/android_commands/android_common.py
new file mode 100644
index 000000000000..43ac7b48d770
--- /dev/null
+++ b/test/asan/android_commands/android_common.py
@@ -0,0 +1,29 @@
+import os, subprocess, tempfile
+import time
+
+ANDROID_TMPDIR = '/data/local/tmp/Output'
+ADB = os.environ.get('ADB', 'adb')
+
+verbose = False
+if os.environ.get('ANDROID_RUN_VERBOSE') == '1':
+ verbose = True
+
+def adb(args):
+ if verbose:
+ print args
+ devnull = open(os.devnull, 'w')
+ return subprocess.call([ADB] + args, stdout=devnull, stderr=subprocess.STDOUT)
+
+def pull_from_device(path):
+ tmp = tempfile.mktemp()
+ adb(['pull', path, tmp])
+ text = open(tmp, 'r').read()
+ os.unlink(tmp)
+ return text
+
+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)])
diff --git a/test/asan/android_commands/android_compile.py b/test/asan/android_commands/android_compile.py
new file mode 100755
index 000000000000..4b880886b0c1
--- /dev/null
+++ b/test/asan/android_commands/android_compile.py
@@ -0,0 +1,36 @@
+#!/usr/bin/python
+
+import os, sys, subprocess
+from android_common import *
+
+
+here = os.path.abspath(os.path.dirname(sys.argv[0]))
+android_run = os.path.join(here, 'android_run.py')
+
+output = None
+output_type = 'executable'
+
+args = sys.argv[1:]
+while args:
+ arg = args.pop(0)
+ if arg == '-shared':
+ output_type = 'shared'
+ elif arg == '-c':
+ output_type = 'object'
+ elif arg == '-o':
+ output = args.pop(0)
+
+if output == None:
+ print "No output file name!"
+ sys.exit(1)
+
+ret = subprocess.call(sys.argv[1:])
+if ret != 0:
+ sys.exit(ret)
+
+if output_type in ['executable', 'shared']:
+ push_to_device(output)
+
+if output_type == 'executable':
+ os.rename(output, output + '.real')
+ os.symlink(android_run, output)
diff --git a/test/asan/android_commands/android_run.py b/test/asan/android_commands/android_run.py
new file mode 100755
index 000000000000..7f8c612a0cf0
--- /dev/null
+++ b/test/asan/android_commands/android_run.py
@@ -0,0 +1,34 @@
+#!/usr/bin/python
+
+import os, sys, subprocess, tempfile
+from android_common import *
+
+ANDROID_TMPDIR = '/data/local/tmp/Output'
+
+here = os.path.abspath(os.path.dirname(sys.argv[0]))
+device_binary = os.path.join(ANDROID_TMPDIR, os.path.basename(sys.argv[0]))
+
+def build_env():
+ args = []
+ # Android linker ignores RPATH. Set LD_LIBRARY_PATH to Output dir.
+ args.append('LD_LIBRARY_PATH=%s:%s' %
+ (ANDROID_TMPDIR, os.environ.get('LD_LIBRARY_PATH', '')))
+ for (key, value) in os.environ.items():
+ if key in ['ASAN_OPTIONS']:
+ args.append('%s="%s"' % (key, value))
+ return ' '.join(args)
+
+device_env = build_env()
+device_args = ' '.join(sys.argv[1:]) # FIXME: escape?
+device_stdout = device_binary + '.stdout'
+device_stderr = device_binary + '.stderr'
+device_exitcode = device_binary + '.exitcode'
+ret = adb(['shell', 'cd %s && %s asanwrapper %s %s >%s 2>%s ; echo $? >%s' %
+ (ANDROID_TMPDIR, device_env, device_binary, device_args,
+ device_stdout, device_stderr, device_exitcode)])
+if ret != 0:
+ sys.exit(ret)
+
+sys.stdout.write(pull_from_device(device_stdout))
+sys.stderr.write(pull_from_device(device_stderr))
+sys.exit(int(pull_from_device(device_exitcode)))
diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg
new file mode 100644
index 000000000000..82a36de9cdda
--- /dev/null
+++ b/test/asan/lit.cfg
@@ -0,0 +1,153 @@
+# -*- Python -*-
+
+import os
+import platform
+
+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
+
+def push_dynamic_library_lookup_path(config, new_path):
+ if platform.system() == 'Windows':
+ dynamic_library_lookup_var = 'PATH'
+ else:
+ dynamic_library_lookup_var = 'LD_LIBRARY_PATH'
+
+ new_ld_library_path = os.path.pathsep.join(
+ (new_path, config.environment[dynamic_library_lookup_var]))
+ config.environment[dynamic_library_lookup_var] = new_ld_library_path
+
+# Setup config name.
+config.name = 'AddressSanitizer' + config.name_suffix
+
+# Setup source root.
+config.test_source_root = os.path.dirname(__file__)
+
+# GCC-ASan doesn't link in all the necessary libraries automatically, so
+# we have to do it ourselves.
+if config.compiler_id == 'GNU':
+ extra_linkflags = ["-pthread", "-lstdc++"]
+else:
+ extra_linkflags = []
+
+# There is no libdl on FreeBSD.
+if config.compiler_id == 'GNU' and config.host_os != 'FreeBSD':
+ extra_linkflags += ["-ldl"]
+
+# Setup default compiler flags used with -fsanitize=address option.
+# FIXME: Review the set of required flags and check if it can be reduced.
+target_cflags = [get_required_attr(config, "target_cflags")] + extra_linkflags
+target_cxxflags = config.cxx_mode_flags + target_cflags
+clang_asan_static_cflags = (["-fsanitize=address",
+ "-mno-omit-leaf-frame-pointer",
+ "-fno-omit-frame-pointer",
+ "-fno-optimize-sibling-calls"] +
+ config.debug_info_flags + target_cflags)
+clang_asan_static_cxxflags = config.cxx_mode_flags + clang_asan_static_cflags
+
+if config.asan_dynamic:
+ clang_asan_cflags = clang_asan_static_cflags + ['-shared-libasan']
+ clang_asan_cxxflags = clang_asan_static_cxxflags + ['-shared-libasan']
+ config.available_features.add("asan-dynamic-runtime")
+else:
+ clang_asan_cflags = clang_asan_static_cflags
+ clang_asan_cxxflags = clang_asan_static_cxxflags
+ config.available_features.add("asan-static-runtime")
+
+asan_lit_source_dir = get_required_attr(config, "asan_lit_source_dir")
+if config.android == "1":
+ config.available_features.add('android')
+ clang_wrapper = os.path.join(asan_lit_source_dir,
+ "android_commands", "android_compile.py") + " "
+else:
+ config.available_features.add('not-android')
+ clang_wrapper = ""
+
+def build_invocation(compile_flags):
+ return " " + " ".join([clang_wrapper, config.clang] + compile_flags) + " "
+
+config.substitutions.append( ("%clang ", build_invocation(target_cflags)) )
+config.substitutions.append( ("%clangxx ", build_invocation(target_cxxflags)) )
+config.substitutions.append( ("%clang_asan ", build_invocation(clang_asan_cflags)) )
+config.substitutions.append( ("%clangxx_asan ", build_invocation(clang_asan_cxxflags)) )
+config.substitutions.append( ("%shared_libasan", "libclang_rt.asan-%s.so" % config.target_arch))
+if config.asan_dynamic:
+ config.substitutions.append( ("%clang_asan_static ", build_invocation(clang_asan_static_cflags)) )
+ config.substitutions.append( ("%clangxx_asan_static ", build_invocation(clang_asan_static_cxxflags)) )
+
+# Windows-specific tests might also use the clang-cl.exe driver.
+if platform.system() == 'Windows':
+ clang_cl_asan_cxxflags = ["-fsanitize=address",
+ "-Wno-deprecated-declarations",
+ "-WX",
+ "-D_HAS_EXCEPTIONS=0",
+ "-Zi"] + target_cflags
+ if config.asan_dynamic:
+ clang_cl_asan_cxxflags.append("-MD")
+ clang_invocation = build_invocation(clang_cl_asan_cxxflags)
+ clang_cl_invocation = clang_invocation.replace("clang.exe","clang-cl.exe")
+ config.substitutions.append( ("%clang_cl_asan ", clang_cl_invocation) )
+ config.substitutions.append( ("%asan_dll_thunk",
+ os.path.join(config.compiler_rt_libdir, "clang_rt.asan_dll_thunk-i386.lib")))
+
+# FIXME: De-hardcode this path.
+asan_source_dir = os.path.join(
+ get_required_attr(config, "compiler_rt_src_root"), "lib", "asan")
+# Setup path to asan_symbolize.py script.
+asan_symbolize = os.path.join(asan_source_dir, "scripts", "asan_symbolize.py")
+if not os.path.exists(asan_symbolize):
+ lit_config.fatal("Can't find script on path %r" % asan_symbolize)
+python_exec = get_required_attr(config, "python_executable")
+config.substitutions.append( ("%asan_symbolize", python_exec + " " + asan_symbolize + " ") )
+# Setup path to sancov.py script.
+sanitizer_common_source_dir = os.path.join(
+ get_required_attr(config, "compiler_rt_src_root"), "lib", "sanitizer_common")
+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 + " ") )
+
+# Determine kernel bitness
+if config.host_arch.find('64') != -1 and config.android != "1":
+ kernel_bits = '64'
+else:
+ kernel_bits = '32'
+
+config.substitutions.append( ('CHECK-%kernel_bits', ("CHECK-kernel-" + kernel_bits + "-bits")))
+
+config.available_features.add("asan-" + config.bits + "-bits")
+
+# Allow tests to use REQUIRES=stable-runtime. For use when you cannot use XFAIL
+# because the test hangs.
+if config.target_arch != 'arm':
+ config.available_features.add('stable-runtime')
+
+# Turn on leak detection on 64-bit Linux.
+if config.host_os == 'Linux' and config.target_arch == 'x86_64':
+ config.available_features.add('leak-detection')
+
+# Set LD_LIBRARY_PATH to pick dynamic runtime up properly.
+push_dynamic_library_lookup_path(config, config.compiler_rt_libdir)
+
+# GCC-ASan uses dynamic runtime by default.
+if config.compiler_id == 'GNU':
+ gcc_dir = os.path.dirname(config.clang)
+ libasan_dir = os.path.join(gcc_dir, "..", "lib" + config.bits)
+ push_dynamic_library_lookup_path(config, libasan_dir)
+
+# Default test suffixes.
+config.suffixes = ['.c', '.cc', '.cpp']
+
+if config.host_os == 'Darwin':
+ config.suffixes.append('.mm')
+
+# AddressSanitizer tests are currently supported on Linux, Darwin and
+# FreeBSD only.
+if config.host_os not in ['Linux', 'Darwin', 'FreeBSD']:
+ config.unsupported = True
diff --git a/test/asan/lit.site.cfg.in b/test/asan/lit.site.cfg.in
new file mode 100644
index 000000000000..332f9ad9f828
--- /dev/null
+++ b/test/asan/lit.site.cfg.in
@@ -0,0 +1,19 @@
+## Autogenerated by LLVM/Clang configuration.
+# Do not edit!
+
+# 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@
+config.target_arch = "@ASAN_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, "@ASAN_LIT_SOURCE_DIR@/lit.cfg")
diff --git a/test/Unit/absvdi2_test.c b/test/builtins/Unit/absvdi2_test.c
index f0bf560681e7..f0bf560681e7 100644
--- a/test/Unit/absvdi2_test.c
+++ b/test/builtins/Unit/absvdi2_test.c
diff --git a/test/Unit/absvsi2_test.c b/test/builtins/Unit/absvsi2_test.c
index 3b88078dfb4a..3b88078dfb4a 100644
--- a/test/Unit/absvsi2_test.c
+++ b/test/builtins/Unit/absvsi2_test.c
diff --git a/test/Unit/absvti2_test.c b/test/builtins/Unit/absvti2_test.c
index 8233c18ff09a..9b71f200ac7b 100644
--- a/test/Unit/absvti2_test.c
+++ b/test/builtins/Unit/absvti2_test.c
@@ -11,12 +11,12 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <stdio.h>
#include <stdlib.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: absolute value
// Effects: aborts if abs(x) < 0
@@ -49,7 +49,7 @@ int test__absvti2(ti_int a)
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
// if (test__absvti2(make_ti(0x8000000000000000LL, 0))) // should abort
// return 1;
diff --git a/test/Unit/adddf3vfp_test.c b/test/builtins/Unit/adddf3vfp_test.c
index 5ad42f7b3a6e..5ad42f7b3a6e 100644
--- a/test/Unit/adddf3vfp_test.c
+++ b/test/builtins/Unit/adddf3vfp_test.c
diff --git a/test/Unit/addsf3vfp_test.c b/test/builtins/Unit/addsf3vfp_test.c
index 95e057c36305..95e057c36305 100644
--- a/test/Unit/addsf3vfp_test.c
+++ b/test/builtins/Unit/addsf3vfp_test.c
diff --git a/test/builtins/Unit/addtf3_test.c b/test/builtins/Unit/addtf3_test.c
new file mode 100644
index 000000000000..4a3aacd96e6d
--- /dev/null
+++ b/test/builtins/Unit/addtf3_test.c
@@ -0,0 +1,81 @@
+//===--------------- addtf3_test.c - Test __addtf3 ------------------------===//
+//
+// The 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 __addtf3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+#if __LDBL_MANT_DIG__ == 113
+
+#include "fp_test.h"
+
+// Returns: a + b
+long double __addtf3(long double a, long double b);
+
+int test__addtf3(long double a, long double b,
+ uint64_t expectedHi, uint64_t expectedLo)
+{
+ long double x = __addtf3(a, b);
+ int ret = compareResultLD(x, expectedHi, expectedLo);
+
+ if (ret){
+ printf("error in test__addtf3(%.20Lf, %.20Lf) = %.20Lf, "
+ "expected %.20Lf\n", a, b, x,
+ fromRep128(expectedHi, expectedLo));
+ }
+
+ return ret;
+}
+
+char assumption_1[sizeof(long double) * CHAR_BIT == 128] = {0};
+
+#endif
+
+int main()
+{
+#if __LDBL_MANT_DIG__ == 113
+ // qNaN + any = qNaN
+ if (test__addtf3(makeQNaN128(),
+ 0x1.23456789abcdefp+5L,
+ UINT64_C(0x7fff800000000000),
+ UINT64_C(0x0)))
+ return 1;
+ // NaN + any = NaN
+ if (test__addtf3(makeNaN128(UINT64_C(0x800030000000)),
+ 0x1.23456789abcdefp+5L,
+ UINT64_C(0x7fff800000000000),
+ UINT64_C(0x0)))
+ return 1;
+ // inf + inf = inf
+ if (test__addtf3(makeInf128(),
+ makeInf128(),
+ UINT64_C(0x7fff000000000000),
+ UINT64_C(0x0)))
+ return 1;
+ // inf + any = inf
+ if (test__addtf3(makeInf128(),
+ 0x1.2335653452436234723489432abcdefp+5L,
+ UINT64_C(0x7fff000000000000),
+ UINT64_C(0x0)))
+ return 1;
+ // any + any
+ if (test__addtf3(0x1.23456734245345543849abcdefp+5L,
+ 0x1.edcba52449872455634654321fp-1L,
+ UINT64_C(0x40042afc95c8b579),
+ UINT64_C(0x61e58dd6c51eb77c)))
+ return 1;
+
+#else
+ printf("skipped\n");
+
+#endif
+ return 0;
+}
diff --git a/test/Unit/addvdi3_test.c b/test/builtins/Unit/addvdi3_test.c
index 0d7271d5a4ae..0d7271d5a4ae 100644
--- a/test/Unit/addvdi3_test.c
+++ b/test/builtins/Unit/addvdi3_test.c
diff --git a/test/Unit/addvsi3_test.c b/test/builtins/Unit/addvsi3_test.c
index 59fd9d2ae15f..59fd9d2ae15f 100644
--- a/test/Unit/addvsi3_test.c
+++ b/test/builtins/Unit/addvsi3_test.c
diff --git a/test/Unit/addvti3_test.c b/test/builtins/Unit/addvti3_test.c
index 1cf066c48917..fe093e3b26a2 100644
--- a/test/Unit/addvti3_test.c
+++ b/test/builtins/Unit/addvti3_test.c
@@ -11,11 +11,11 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: a + b
// Effects: aborts if a + b overflows
@@ -48,7 +48,7 @@ int test__addvti3(ti_int a, ti_int b)
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
// should abort
// test__addvti3(make_ti(0x8000000000000000LL, 0x0000000000000000LL),
// make_ti(0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFFFFFFFFLL));
diff --git a/test/Unit/ashldi3_test.c b/test/builtins/Unit/ashldi3_test.c
index fb80c6f77e40..fb80c6f77e40 100644
--- a/test/Unit/ashldi3_test.c
+++ b/test/builtins/Unit/ashldi3_test.c
diff --git a/test/Unit/ashlti3_test.c b/test/builtins/Unit/ashlti3_test.c
index b9f4dcc0a8c7..2361d16b3699 100644
--- a/test/Unit/ashlti3_test.c
+++ b/test/builtins/Unit/ashlti3_test.c
@@ -11,11 +11,11 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: a << b
// Precondition: 0 <= b < bits_in_tword
@@ -49,7 +49,7 @@ char assumption_1[sizeof(ti_int) == 2*sizeof(di_int)] = {0};
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
if (test__ashlti3(make_ti(0xFEDCBA9876543215LL, 0xFEDCBA9876543215LL), 0,
make_ti(0xFEDCBA9876543215LL, 0xFEDCBA9876543215LL)))
return 1;
diff --git a/test/Unit/ashrdi3_test.c b/test/builtins/Unit/ashrdi3_test.c
index ac517e191880..ac517e191880 100644
--- a/test/Unit/ashrdi3_test.c
+++ b/test/builtins/Unit/ashrdi3_test.c
diff --git a/test/Unit/ashrti3_test.c b/test/builtins/Unit/ashrti3_test.c
index 3abee36b6b7d..62ba1017ecd9 100644
--- a/test/Unit/ashrti3_test.c
+++ b/test/builtins/Unit/ashrti3_test.c
@@ -11,11 +11,11 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: arithmetic a >> b
// Precondition: 0 <= b < bits_in_tword
@@ -47,7 +47,7 @@ char assumption_1[sizeof(ti_int) == 2*sizeof(di_int)] = {0};
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
if (test__ashrti3(make_ti(0xFEDCBA9876543215LL, 0xFEDCBA9876543215LL), 0,
make_ti(0xFEDCBA9876543215LL, 0xFEDCBA9876543215LL)))
return 1;
diff --git a/test/Unit/bswapdi2_test.c b/test/builtins/Unit/bswapdi2_test.c
index 2d830cf5e41e..2d830cf5e41e 100644
--- a/test/Unit/bswapdi2_test.c
+++ b/test/builtins/Unit/bswapdi2_test.c
diff --git a/test/Unit/bswapsi2_test.c b/test/builtins/Unit/bswapsi2_test.c
index 4488a888e1eb..4488a888e1eb 100644
--- a/test/Unit/bswapsi2_test.c
+++ b/test/builtins/Unit/bswapsi2_test.c
diff --git a/test/Unit/clear_cache_test.c b/test/builtins/Unit/clear_cache_test.c
index 3507fd80b288..3507fd80b288 100644
--- a/test/Unit/clear_cache_test.c
+++ b/test/builtins/Unit/clear_cache_test.c
diff --git a/test/Unit/clzdi2_test.c b/test/builtins/Unit/clzdi2_test.c
index 58403f091f48..58403f091f48 100644
--- a/test/Unit/clzdi2_test.c
+++ b/test/builtins/Unit/clzdi2_test.c
diff --git a/test/Unit/clzsi2_test.c b/test/builtins/Unit/clzsi2_test.c
index cc1da64b03ef..cc1da64b03ef 100644
--- a/test/Unit/clzsi2_test.c
+++ b/test/builtins/Unit/clzsi2_test.c
diff --git a/test/Unit/clzti2_test.c b/test/builtins/Unit/clzti2_test.c
index d2ca1645dd1a..5a0e3e8b1e98 100644
--- a/test/Unit/clzti2_test.c
+++ b/test/builtins/Unit/clzti2_test.c
@@ -11,11 +11,11 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: the number of leading 0-bits
// Precondition: a != 0
@@ -41,7 +41,7 @@ char assumption_1[sizeof(ti_int) == 2*sizeof(di_int)] = {0};
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
const int N = (int)(sizeof(ti_int) * CHAR_BIT);
if (test__clzti2(0x00000001, N-1))
diff --git a/test/Unit/cmpdi2_test.c b/test/builtins/Unit/cmpdi2_test.c
index 609ab1a63a61..609ab1a63a61 100644
--- a/test/Unit/cmpdi2_test.c
+++ b/test/builtins/Unit/cmpdi2_test.c
diff --git a/test/Unit/cmpti2_test.c b/test/builtins/Unit/cmpti2_test.c
index 4339e0abb5e9..15ee4fc68d53 100644
--- a/test/Unit/cmpti2_test.c
+++ b/test/builtins/Unit/cmpti2_test.c
@@ -11,11 +11,11 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: if (a < b) returns 0
// if (a == b) returns 1
// if (a > b) returns 2
@@ -43,7 +43,7 @@ char assumption_1[sizeof(ti_int) == 2*sizeof(di_int)] = {0};
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
if (test__cmpti2(0, 0, 1))
return 1;
if (test__cmpti2(1, 1, 1))
diff --git a/test/Unit/comparedf2_test.c b/test/builtins/Unit/comparedf2_test.c
index 662372290290..662372290290 100644
--- a/test/Unit/comparedf2_test.c
+++ b/test/builtins/Unit/comparedf2_test.c
diff --git a/test/Unit/comparesf2_test.c b/test/builtins/Unit/comparesf2_test.c
index 026e90053bcf..026e90053bcf 100644
--- a/test/Unit/comparesf2_test.c
+++ b/test/builtins/Unit/comparesf2_test.c
diff --git a/test/Unit/ctzdi2_test.c b/test/builtins/Unit/ctzdi2_test.c
index 1f2d101a1943..1f2d101a1943 100644
--- a/test/Unit/ctzdi2_test.c
+++ b/test/builtins/Unit/ctzdi2_test.c
diff --git a/test/Unit/ctzsi2_test.c b/test/builtins/Unit/ctzsi2_test.c
index 36f221595b68..36f221595b68 100644
--- a/test/Unit/ctzsi2_test.c
+++ b/test/builtins/Unit/ctzsi2_test.c
diff --git a/test/Unit/ctzti2_test.c b/test/builtins/Unit/ctzti2_test.c
index c4934bd254b7..9a972f9e2f94 100644
--- a/test/Unit/ctzti2_test.c
+++ b/test/builtins/Unit/ctzti2_test.c
@@ -11,11 +11,11 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: the number of trailing 0-bits
// Precondition: a != 0
@@ -41,7 +41,7 @@ char assumption_1[sizeof(ti_int) == 2*sizeof(di_int)] = {0};
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
if (test__ctzti2(0x00000001, 0))
return 1;
if (test__ctzti2(0x00000002, 1))
diff --git a/test/Unit/divdc3_test.c b/test/builtins/Unit/divdc3_test.c
index 9224cddceeb8..9224cddceeb8 100644
--- a/test/Unit/divdc3_test.c
+++ b/test/builtins/Unit/divdc3_test.c
diff --git a/test/Unit/divdf3vfp_test.c b/test/builtins/Unit/divdf3vfp_test.c
index e13822ffcaa0..e13822ffcaa0 100644
--- a/test/Unit/divdf3vfp_test.c
+++ b/test/builtins/Unit/divdf3vfp_test.c
diff --git a/test/Unit/divdi3_test.c b/test/builtins/Unit/divdi3_test.c
index c25f917a419e..c25f917a419e 100644
--- a/test/Unit/divdi3_test.c
+++ b/test/builtins/Unit/divdi3_test.c
diff --git a/test/Unit/divmodsi4_test.c b/test/builtins/Unit/divmodsi4_test.c
index bea31ea9a445..bea31ea9a445 100644
--- a/test/Unit/divmodsi4_test.c
+++ b/test/builtins/Unit/divmodsi4_test.c
diff --git a/test/Unit/divsc3_test.c b/test/builtins/Unit/divsc3_test.c
index 9d060a2d1489..9d060a2d1489 100644
--- a/test/Unit/divsc3_test.c
+++ b/test/builtins/Unit/divsc3_test.c
diff --git a/test/Unit/divsf3vfp_test.c b/test/builtins/Unit/divsf3vfp_test.c
index 8382558412cf..8382558412cf 100644
--- a/test/Unit/divsf3vfp_test.c
+++ b/test/builtins/Unit/divsf3vfp_test.c
diff --git a/test/Unit/divsi3_test.c b/test/builtins/Unit/divsi3_test.c
index 6fda54ff37ec..6fda54ff37ec 100644
--- a/test/Unit/divsi3_test.c
+++ b/test/builtins/Unit/divsi3_test.c
diff --git a/test/Unit/divtc3_test.c b/test/builtins/Unit/divtc3_test.c
index 7bb74d755146..7bb74d755146 100644
--- a/test/Unit/divtc3_test.c
+++ b/test/builtins/Unit/divtc3_test.c
diff --git a/test/builtins/Unit/divtf3_test.c b/test/builtins/Unit/divtf3_test.c
new file mode 100644
index 000000000000..dad631cc4f17
--- /dev/null
+++ b/test/builtins/Unit/divtf3_test.c
@@ -0,0 +1,94 @@
+//===--------------- divtf3_test.c - Test __divtf3 ------------------------===//
+//
+// The 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 __divtf3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+#if __LDBL_MANT_DIG__ == 113
+
+#include "fp_test.h"
+
+// Returns: a / b
+long double __divtf3(long double a, long double b);
+
+int test__divtf3(long double a, long double b,
+ uint64_t expectedHi, uint64_t expectedLo)
+{
+ long double x = __divtf3(a, b);
+ int ret = compareResultLD(x, expectedHi, expectedLo);
+
+ if (ret){
+ printf("error in test__divtf3(%.20Lf, %.20Lf) = %.20Lf, "
+ "expected %.20Lf\n", a, b, x,
+ fromRep128(expectedHi, expectedLo));
+ }
+ return ret;
+}
+
+char assumption_1[sizeof(long double) * CHAR_BIT == 128] = {0};
+
+#endif
+
+int main()
+{
+#if __LDBL_MANT_DIG__ == 113
+ // qNaN / any = qNaN
+ if (test__divtf3(makeQNaN128(),
+ 0x1.23456789abcdefp+5L,
+ UINT64_C(0x7fff800000000000),
+ UINT64_C(0x0)))
+ return 1;
+ // NaN / any = NaN
+ if (test__divtf3(makeNaN128(UINT64_C(0x800030000000)),
+ 0x1.23456789abcdefp+5L,
+ UINT64_C(0x7fff800000000000),
+ UINT64_C(0x0)))
+ return 1;
+ // inf / any = inf
+ if (test__divtf3(makeInf128(),
+ 0x1.23456789abcdefp+5L,
+ UINT64_C(0x7fff000000000000),
+ UINT64_C(0x0)))
+ return 1;
+ // any / any
+ if (test__divtf3(0x1.a23b45362464523375893ab4cdefp+5L,
+ 0x1.eedcbaba3a94546558237654321fp-1L,
+ UINT64_C(0x4004b0b72924d407),
+ UINT64_C(0x0717e84356c6eba2)))
+ return 1;
+ if (test__divtf3(0x1.a2b34c56d745382f9abf2c3dfeffp-50L,
+ 0x1.ed2c3ba15935332532287654321fp-9L,
+ UINT64_C(0x3fd5b2af3f828c9b),
+ UINT64_C(0x40e51f64cde8b1f2)))
+ return 15;
+ if (test__divtf3(0x1.2345f6aaaa786555f42432abcdefp+456L,
+ 0x1.edacbba9874f765463544dd3621fp+6400L,
+ UINT64_C(0x28c62e15dc464466),
+ UINT64_C(0xb5a07586348557ac)))
+ return 1;
+ if (test__divtf3(0x1.2d3456f789ba6322bc665544edefp-234L,
+ 0x1.eddcdba39f3c8b7a36564354321fp-4455L,
+ UINT64_C(0x507b38442b539266),
+ UINT64_C(0x22ce0f1d024e1252)))
+ return 1;
+ if (test__divtf3(0x1.2345f6b77b7a8953365433abcdefp+234L,
+ 0x1.edcba987d6bb3aa467754354321fp-4055L,
+ UINT64_C(0x50bf2e02f0798d36),
+ UINT64_C(0x5e6fcb6b60044078)))
+ return 1;
+
+#else
+ printf("skipped\n");
+
+#endif
+ return 0;
+}
diff --git a/test/Unit/divti3_test.c b/test/builtins/Unit/divti3_test.c
index 7c8e2970fa6e..bc81c2a5418d 100644
--- a/test/Unit/divti3_test.c
+++ b/test/builtins/Unit/divti3_test.c
@@ -11,11 +11,11 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: a / b
ti_int __divti3(ti_int a, ti_int b);
@@ -47,7 +47,7 @@ char assumption_1[sizeof(ti_int) == 2*sizeof(di_int)] = {0};
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
if (test__divti3(0, 1, 0))
return 1;
if (test__divti3(0, -1, 0))
diff --git a/test/Unit/divxc3_test.c b/test/builtins/Unit/divxc3_test.c
index aa8a7625d139..aa8a7625d139 100644
--- a/test/Unit/divxc3_test.c
+++ b/test/builtins/Unit/divxc3_test.c
diff --git a/test/Unit/enable_execute_stack_test.c b/test/builtins/Unit/enable_execute_stack_test.c
index c0f67b337939..c0f67b337939 100644
--- a/test/Unit/enable_execute_stack_test.c
+++ b/test/builtins/Unit/enable_execute_stack_test.c
diff --git a/test/Unit/endianness.h b/test/builtins/Unit/endianness.h
index 06c53de0bfa9..06c53de0bfa9 100644
--- a/test/Unit/endianness.h
+++ b/test/builtins/Unit/endianness.h
diff --git a/test/Unit/eqdf2vfp_test.c b/test/builtins/Unit/eqdf2vfp_test.c
index 585bd08e9789..585bd08e9789 100644
--- a/test/Unit/eqdf2vfp_test.c
+++ b/test/builtins/Unit/eqdf2vfp_test.c
diff --git a/test/Unit/eqsf2vfp_test.c b/test/builtins/Unit/eqsf2vfp_test.c
index b0eed9402a37..b0eed9402a37 100644
--- a/test/Unit/eqsf2vfp_test.c
+++ b/test/builtins/Unit/eqsf2vfp_test.c
diff --git a/test/builtins/Unit/eqtf2_test.c b/test/builtins/Unit/eqtf2_test.c
new file mode 100644
index 000000000000..038583503ab2
--- /dev/null
+++ b/test/builtins/Unit/eqtf2_test.c
@@ -0,0 +1,89 @@
+//===------------ eqtf2_test.c - Test __eqtf2------------------------------===//
+//
+// The 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 __eqtf2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+#if __LP64__ && __LDBL_MANT_DIG__ == 113
+
+#include "fp_test.h"
+
+int __eqtf2(long double a, long double b);
+
+int test__eqtf2(long double a, long double b, enum EXPECTED_RESULT expected)
+{
+ int x = __eqtf2(a, b);
+ int ret = compareResultCMP(x, expected);
+
+ if (ret){
+ printf("error in test__eqtf2(%.20Lf, %.20Lf) = %d, "
+ "expected %s\n", a, b, x, expectedStr(expected));
+ }
+ return ret;
+}
+
+char assumption_1[sizeof(long double) * CHAR_BIT == 128] = {0};
+
+#endif
+
+int main()
+{
+#if __LP64__ && __LDBL_MANT_DIG__ == 113
+ // NaN
+ if (test__eqtf2(makeQNaN128(),
+ 0x1.234567890abcdef1234567890abcp+3L,
+ NEQUAL_0))
+ return 1;
+ // <
+ // exp
+ if (test__eqtf2(0x1.234567890abcdef1234567890abcp-3L,
+ 0x1.234567890abcdef1234567890abcp+3L,
+ NEQUAL_0))
+ return 1;
+ // mantissa
+ if (test__eqtf2(0x1.234567890abcdef1234567890abcp+3L,
+ 0x1.334567890abcdef1234567890abcp+3L,
+ NEQUAL_0))
+ return 1;
+ // sign
+ if (test__eqtf2(-0x1.234567890abcdef1234567890abcp+3L,
+ 0x1.234567890abcdef1234567890abcp+3L,
+ NEQUAL_0))
+ return 1;
+ // ==
+ if (test__eqtf2(0x1.234567890abcdef1234567890abcp+3L,
+ 0x1.234567890abcdef1234567890abcp+3L,
+ EQUAL_0))
+ return 1;
+ // >
+ // exp
+ if (test__eqtf2(0x1.234567890abcdef1234567890abcp+3L,
+ 0x1.234567890abcdef1234567890abcp-3L,
+ NEQUAL_0))
+ return 1;
+ // mantissa
+ if (test__eqtf2(0x1.334567890abcdef1234567890abcp+3L,
+ 0x1.234567890abcdef1234567890abcp+3L,
+ NEQUAL_0))
+ return 1;
+ // sign
+ if (test__eqtf2(0x1.234567890abcdef1234567890abcp+3L,
+ -0x1.234567890abcdef1234567890abcp+3L,
+ NEQUAL_0))
+ return 1;
+
+#else
+ printf("skipped\n");
+
+#endif
+ return 0;
+}
diff --git a/test/Unit/extebdsfdf2vfp_test.c b/test/builtins/Unit/extebdsfdf2vfp_test.c
index 3a009cf2d7f8..3a009cf2d7f8 100644
--- a/test/Unit/extebdsfdf2vfp_test.c
+++ b/test/builtins/Unit/extebdsfdf2vfp_test.c
diff --git a/test/builtins/Unit/extenddftf2_test.c b/test/builtins/Unit/extenddftf2_test.c
new file mode 100644
index 000000000000..05acc08c0951
--- /dev/null
+++ b/test/builtins/Unit/extenddftf2_test.c
@@ -0,0 +1,82 @@
+//===--------------- extenddftf2_test.c - Test __extenddftf2 --------------===//
+//
+// The 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 __extenddftf2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+#if __LDBL_MANT_DIG__ == 113
+
+#include "fp_test.h"
+
+long double __extenddftf2(double a);
+
+int test__extenddftf2(double a, uint64_t expectedHi, uint64_t expectedLo)
+{
+ long double x = __extenddftf2(a);
+ int ret = compareResultLD(x, expectedHi, expectedLo);
+
+ if (ret){
+ printf("error in test__extenddftf2(%f) = %.20Lf, "
+ "expected %.20Lf\n", a, x, fromRep128(expectedHi, expectedLo));
+ }
+ return ret;
+}
+
+char assumption_1[sizeof(long double) * CHAR_BIT == 128] = {0};
+
+#endif
+
+int main()
+{
+#if __LDBL_MANT_DIG__ == 113
+ // qNaN
+ if (test__extenddftf2(makeQNaN64(),
+ UINT64_C(0x7fff800000000000),
+ UINT64_C(0x0)))
+ return 1;
+ // NaN
+ if (test__extenddftf2(makeNaN64(UINT64_C(0x7100000000000)),
+ UINT64_C(0x7fff710000000000),
+ UINT64_C(0x0)))
+ return 1;
+ // inf
+ if (test__extenddftf2(makeInf64(),
+ UINT64_C(0x7fff000000000000),
+ UINT64_C(0x0)))
+ return 1;
+ // zero
+ if (test__extenddftf2(0.0, UINT64_C(0x0), UINT64_C(0x0)))
+ return 1;
+
+ if (test__extenddftf2(0x1.23456789abcdefp+5,
+ UINT64_C(0x400423456789abcd),
+ UINT64_C(0xf000000000000000)))
+ return 1;
+ if (test__extenddftf2(0x1.edcba987654321fp-9,
+ UINT64_C(0x3ff6edcba9876543),
+ UINT64_C(0x2000000000000000)))
+ return 1;
+ if (test__extenddftf2(0x1.23456789abcdefp+45,
+ UINT64_C(0x402c23456789abcd),
+ UINT64_C(0xf000000000000000)))
+ return 1;
+ if (test__extenddftf2(0x1.edcba987654321fp-45,
+ UINT64_C(0x3fd2edcba9876543),
+ UINT64_C(0x2000000000000000)))
+ return 1;
+
+#else
+ printf("skipped\n");
+
+#endif
+ return 0;
+}
diff --git a/test/builtins/Unit/extendsftf2_test.c b/test/builtins/Unit/extendsftf2_test.c
new file mode 100644
index 000000000000..5f41928b862f
--- /dev/null
+++ b/test/builtins/Unit/extendsftf2_test.c
@@ -0,0 +1,83 @@
+//===--------------- extendsftf2_test.c - Test __extendsftf2 --------------===//
+//
+// The 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 __extendsftf2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+#if __LDBL_MANT_DIG__ == 113
+
+#include "fp_test.h"
+
+long double __extendsftf2(float a);
+
+int test__extendsftf2(float a, uint64_t expectedHi, uint64_t expectedLo)
+{
+ long double x = __extendsftf2(a);
+ int ret = compareResultLD(x, expectedHi, expectedLo);
+
+ if (ret)
+ {
+ printf("error in test__extendsftf2(%f) = %.20Lf, "
+ "expected %.20Lf\n", a, x, fromRep128(expectedHi, expectedLo));
+ }
+ return ret;
+}
+
+char assumption_1[sizeof(long double) * CHAR_BIT == 128] = {0};
+
+#endif
+
+int main()
+{
+#if __LDBL_MANT_DIG__ == 113
+ // qNaN
+ if (test__extendsftf2(makeQNaN32(),
+ UINT64_C(0x7fff800000000000),
+ UINT64_C(0x0)))
+ return 1;
+ // NaN
+ if (test__extendsftf2(makeNaN32(UINT32_C(0x410000)),
+ UINT64_C(0x7fff820000000000),
+ UINT64_C(0x0)))
+ return 1;
+ // inf
+ if (test__extendsftf2(makeInf32(),
+ UINT64_C(0x7fff000000000000),
+ UINT64_C(0x0)))
+ return 1;
+ // zero
+ if (test__extendsftf2(0.0f, UINT64_C(0x0), UINT64_C(0x0)))
+ return 1;
+
+ if (test__extendsftf2(0x1.23456p+5f,
+ UINT64_C(0x4004234560000000),
+ UINT64_C(0x0)))
+ return 1;
+ if (test__extendsftf2(0x1.edcbap-9f,
+ UINT64_C(0x3ff6edcba0000000),
+ UINT64_C(0x0)))
+ return 1;
+ if (test__extendsftf2(0x1.23456p+45f,
+ UINT64_C(0x402c234560000000),
+ UINT64_C(0x0)))
+ return 1;
+ if (test__extendsftf2(0x1.edcbap-45f,
+ UINT64_C(0x3fd2edcba0000000),
+ UINT64_C(0x0)))
+ return 1;
+
+#else
+ printf("skipped\n");
+
+#endif
+ return 0;
+}
diff --git a/test/Unit/ffsdi2_test.c b/test/builtins/Unit/ffsdi2_test.c
index 9041127d1a62..9041127d1a62 100644
--- a/test/Unit/ffsdi2_test.c
+++ b/test/builtins/Unit/ffsdi2_test.c
diff --git a/test/Unit/ffsti2_test.c b/test/builtins/Unit/ffsti2_test.c
index fcb5c2725f26..f944ed0a1e45 100644
--- a/test/Unit/ffsti2_test.c
+++ b/test/builtins/Unit/ffsti2_test.c
@@ -11,11 +11,11 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: the index of the least significant 1-bit in a, or
// the value zero if a is zero. The least significant bit is index one.
@@ -40,7 +40,7 @@ char assumption_1[sizeof(ti_int) == 2*sizeof(di_int)] = {0};
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
if (test__ffsti2(0x00000000, 0))
return 1;
if (test__ffsti2(0x00000001, 1))
diff --git a/test/Unit/fixdfdi_test.c b/test/builtins/Unit/fixdfdi_test.c
index d08afe3a5336..d08afe3a5336 100644
--- a/test/Unit/fixdfdi_test.c
+++ b/test/builtins/Unit/fixdfdi_test.c
diff --git a/test/Unit/fixdfsivfp_test.c b/test/builtins/Unit/fixdfsivfp_test.c
index c6102e274ee5..c6102e274ee5 100644
--- a/test/Unit/fixdfsivfp_test.c
+++ b/test/builtins/Unit/fixdfsivfp_test.c
diff --git a/test/Unit/fixdfti_test.c b/test/builtins/Unit/fixdfti_test.c
index 98a5628edddf..bfa88fd70e14 100644
--- a/test/Unit/fixdfti_test.c
+++ b/test/builtins/Unit/fixdfti_test.c
@@ -11,11 +11,11 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: convert a to a signed long long, rounding toward zero.
// Assumption: double is a IEEE 64 bit floating point type
@@ -49,7 +49,7 @@ char assumption_3[sizeof(double)*CHAR_BIT == 64] = {0};
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
if (test__fixdfti(0.0, 0))
return 1;
diff --git a/test/Unit/fixsfdi_test.c b/test/builtins/Unit/fixsfdi_test.c
index d3e934a5c02a..d3e934a5c02a 100644
--- a/test/Unit/fixsfdi_test.c
+++ b/test/builtins/Unit/fixsfdi_test.c
diff --git a/test/Unit/fixsfsivfp_test.c b/test/builtins/Unit/fixsfsivfp_test.c
index 9abf5e856476..9abf5e856476 100644
--- a/test/Unit/fixsfsivfp_test.c
+++ b/test/builtins/Unit/fixsfsivfp_test.c
diff --git a/test/Unit/fixsfti_test.c b/test/builtins/Unit/fixsfti_test.c
index 5fdd00578528..2b0b99774819 100644
--- a/test/Unit/fixsfti_test.c
+++ b/test/builtins/Unit/fixsfti_test.c
@@ -11,11 +11,11 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: convert a to a signed long long, rounding toward zero.
// Assumption: float is a IEEE 32 bit floating point type
@@ -49,7 +49,7 @@ char assumption_3[sizeof(float)*CHAR_BIT == 32] = {0};
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
if (test__fixsfti(0.0F, 0))
return 1;
diff --git a/test/Unit/fixunsdfdi_test.c b/test/builtins/Unit/fixunsdfdi_test.c
index 0803fd28f5bb..0803fd28f5bb 100644
--- a/test/Unit/fixunsdfdi_test.c
+++ b/test/builtins/Unit/fixunsdfdi_test.c
diff --git a/test/Unit/fixunsdfsi_test.c b/test/builtins/Unit/fixunsdfsi_test.c
index 54fe35b5c35a..54fe35b5c35a 100644
--- a/test/Unit/fixunsdfsi_test.c
+++ b/test/builtins/Unit/fixunsdfsi_test.c
diff --git a/test/Unit/fixunsdfsivfp_test.c b/test/builtins/Unit/fixunsdfsivfp_test.c
index 3727cf7b02fb..3727cf7b02fb 100644
--- a/test/Unit/fixunsdfsivfp_test.c
+++ b/test/builtins/Unit/fixunsdfsivfp_test.c
diff --git a/test/Unit/fixunsdfti_test.c b/test/builtins/Unit/fixunsdfti_test.c
index 1e44b82660c3..9f89de493680 100644
--- a/test/Unit/fixunsdfti_test.c
+++ b/test/builtins/Unit/fixunsdfti_test.c
@@ -24,7 +24,7 @@
// seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
-#if __x86_64
+#ifdef CRT_HAS_128BIT
tu_int __fixunsdfti(double a);
@@ -51,7 +51,7 @@ char assumption_3[sizeof(double)*CHAR_BIT == 64] = {0};
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
if (test__fixunsdfti(0.0, 0))
return 1;
diff --git a/test/Unit/fixunssfdi_test.c b/test/builtins/Unit/fixunssfdi_test.c
index ac89be7bbb27..ac89be7bbb27 100644
--- a/test/Unit/fixunssfdi_test.c
+++ b/test/builtins/Unit/fixunssfdi_test.c
diff --git a/test/Unit/fixunssfsi_test.c b/test/builtins/Unit/fixunssfsi_test.c
index ce6a9287515f..ce6a9287515f 100644
--- a/test/Unit/fixunssfsi_test.c
+++ b/test/builtins/Unit/fixunssfsi_test.c
diff --git a/test/Unit/fixunssfsivfp_test.c b/test/builtins/Unit/fixunssfsivfp_test.c
index c8e45f408b63..c8e45f408b63 100644
--- a/test/Unit/fixunssfsivfp_test.c
+++ b/test/builtins/Unit/fixunssfsivfp_test.c
diff --git a/test/Unit/fixunssfti_test.c b/test/builtins/Unit/fixunssfti_test.c
index cc5e44ba59ed..7965b9500d05 100644
--- a/test/Unit/fixunssfti_test.c
+++ b/test/builtins/Unit/fixunssfti_test.c
@@ -11,11 +11,11 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: convert a to a unsigned long long, rounding toward zero.
// Negative values all become zero.
@@ -51,7 +51,7 @@ char assumption_3[sizeof(float)*CHAR_BIT == 32] = {0};
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
if (test__fixunssfti(0.0F, 0))
return 1;
diff --git a/test/Unit/fixunstfdi_test.c b/test/builtins/Unit/fixunstfdi_test.c
index d0a5db7a9c97..d0a5db7a9c97 100644
--- a/test/Unit/fixunstfdi_test.c
+++ b/test/builtins/Unit/fixunstfdi_test.c
diff --git a/test/Unit/fixunsxfdi_test.c b/test/builtins/Unit/fixunsxfdi_test.c
index 4308f6f4ef1f..4308f6f4ef1f 100644
--- a/test/Unit/fixunsxfdi_test.c
+++ b/test/builtins/Unit/fixunsxfdi_test.c
diff --git a/test/Unit/fixunsxfsi_test.c b/test/builtins/Unit/fixunsxfsi_test.c
index cb2a7f487210..cb2a7f487210 100644
--- a/test/Unit/fixunsxfsi_test.c
+++ b/test/builtins/Unit/fixunsxfsi_test.c
diff --git a/test/Unit/fixunsxfti_test.c b/test/builtins/Unit/fixunsxfti_test.c
index 0e3c842bc022..7d18b1267b3a 100644
--- a/test/Unit/fixunsxfti_test.c
+++ b/test/builtins/Unit/fixunsxfti_test.c
@@ -11,11 +11,11 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: convert a to a unsigned long long, rounding toward zero.
// Negative values all become zero.
@@ -52,7 +52,7 @@ char assumption_3[sizeof(long double)*CHAR_BIT == 128] = {0};
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
if (test__fixunsxfti(0.0, 0))
return 1;
diff --git a/test/Unit/fixxfdi_test.c b/test/builtins/Unit/fixxfdi_test.c
index 43ac0f8aaa3c..43ac0f8aaa3c 100644
--- a/test/Unit/fixxfdi_test.c
+++ b/test/builtins/Unit/fixxfdi_test.c
diff --git a/test/Unit/fixxfti_test.c b/test/builtins/Unit/fixxfti_test.c
index 11296b036871..87914c5341bd 100644
--- a/test/Unit/fixxfti_test.c
+++ b/test/builtins/Unit/fixxfti_test.c
@@ -11,11 +11,11 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: convert a to a signed long long, rounding toward zero.
// Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
@@ -50,7 +50,7 @@ char assumption_3[sizeof(long double)*CHAR_BIT == 128] = {0};
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
if (test__fixxfti(0.0, 0))
return 1;
diff --git a/test/Unit/floatdidf_test.c b/test/builtins/Unit/floatdidf_test.c
index af3dacd4f38b..af3dacd4f38b 100644
--- a/test/Unit/floatdidf_test.c
+++ b/test/builtins/Unit/floatdidf_test.c
diff --git a/test/Unit/floatdisf_test.c b/test/builtins/Unit/floatdisf_test.c
index 3e71df7b2228..3e71df7b2228 100644
--- a/test/Unit/floatdisf_test.c
+++ b/test/builtins/Unit/floatdisf_test.c
diff --git a/test/Unit/floatdixf_test.c b/test/builtins/Unit/floatdixf_test.c
index 337666426318..337666426318 100644
--- a/test/Unit/floatdixf_test.c
+++ b/test/builtins/Unit/floatdixf_test.c
diff --git a/test/Unit/floatsidfvfp_test.c b/test/builtins/Unit/floatsidfvfp_test.c
index e21ecda59945..e21ecda59945 100644
--- a/test/Unit/floatsidfvfp_test.c
+++ b/test/builtins/Unit/floatsidfvfp_test.c
diff --git a/test/Unit/floatsisfvfp_test.c b/test/builtins/Unit/floatsisfvfp_test.c
index d20905bd91e3..d20905bd91e3 100644
--- a/test/Unit/floatsisfvfp_test.c
+++ b/test/builtins/Unit/floatsisfvfp_test.c
diff --git a/test/builtins/Unit/floatsitf_test.c b/test/builtins/Unit/floatsitf_test.c
new file mode 100644
index 000000000000..db4d020af2a9
--- /dev/null
+++ b/test/builtins/Unit/floatsitf_test.c
@@ -0,0 +1,58 @@
+//===--------------- floatsitf_test.c - Test __floatsitf ------------------===//
+//
+// The 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 __floatsitf for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+#if __LDBL_MANT_DIG__ == 113
+
+#include "fp_test.h"
+
+long double __floatsitf(int a);
+
+int test__floatsitf(int a, uint64_t expectedHi, uint64_t expectedLo)
+{
+ long double x = __floatsitf(a);
+ int ret = compareResultLD(x, expectedHi, expectedLo);
+
+ if (ret)
+ {
+ printf("error in test__floatsitf(%d) = %.20Lf, "
+ "expected %.20Lf\n", a, x, fromRep128(expectedHi, expectedLo));
+ }
+ return ret;
+}
+
+char assumption_1[sizeof(long double) * CHAR_BIT == 128] = {0};
+
+#endif
+
+int main()
+{
+#if __LDBL_MANT_DIG__ == 113
+ if (test__floatsitf(0x7fffffff, UINT64_C(0x401dfffffffc0000), UINT64_C(0x0)))
+ return 1;
+ if (test__floatsitf(0, UINT64_C(0x0), UINT64_C(0x0)))
+ return 1;
+ if (test__floatsitf(0xffffffff, UINT64_C(0xbfff000000000000), UINT64_C(0x0)))
+ return 1;
+ if (test__floatsitf(0x12345678, UINT64_C(0x401b234567800000), UINT64_C(0x0)))
+ return 1;
+ if (test__floatsitf(-0x12345678, UINT64_C(0xc01b234567800000), UINT64_C(0x0)))
+ return 1;
+
+#else
+ printf("skipped\n");
+
+#endif
+ return 0;
+}
diff --git a/test/Unit/floattidf_test.c b/test/builtins/Unit/floattidf_test.c
index cfe40849960d..476304f96f10 100644
--- a/test/Unit/floattidf_test.c
+++ b/test/builtins/Unit/floattidf_test.c
@@ -11,12 +11,12 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <float.h>
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: convert a to a double, rounding toward even.
// Assumption: double is a IEEE 64 bit floating point type
@@ -47,7 +47,7 @@ char assumption_3[sizeof(double)*CHAR_BIT == 64] = {0};
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
if (test__floattidf(0, 0.0))
return 1;
diff --git a/test/Unit/floattisf_test.c b/test/builtins/Unit/floattisf_test.c
index a83ec63a25c9..75b8e917f76d 100644
--- a/test/Unit/floattisf_test.c
+++ b/test/builtins/Unit/floattisf_test.c
@@ -11,12 +11,12 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <float.h>
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: convert a to a float, rounding toward even.
// Assumption: float is a IEEE 32 bit floating point type
@@ -47,7 +47,7 @@ char assumption_3[sizeof(float)*CHAR_BIT == 32] = {0};
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
if (test__floattisf(0, 0.0F))
return 1;
diff --git a/test/Unit/floattixf_test.c b/test/builtins/Unit/floattixf_test.c
index 4a9dfb56ac93..ce3566867a47 100644
--- a/test/Unit/floattixf_test.c
+++ b/test/builtins/Unit/floattixf_test.c
@@ -11,12 +11,12 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <float.h>
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: convert a to a long double, rounding toward even.
// Assumption: long double is a IEEE 80 bit floating point type padded to 128 bits
@@ -48,7 +48,7 @@ char assumption_3[sizeof(long double)*CHAR_BIT == 128] = {0};
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
if (test__floattixf(0, 0.0))
return 1;
diff --git a/test/Unit/floatundidf_test.c b/test/builtins/Unit/floatundidf_test.c
index ae91ac374eb0..ae91ac374eb0 100644
--- a/test/Unit/floatundidf_test.c
+++ b/test/builtins/Unit/floatundidf_test.c
diff --git a/test/Unit/floatundisf_test.c b/test/builtins/Unit/floatundisf_test.c
index 394c945a3919..394c945a3919 100644
--- a/test/Unit/floatundisf_test.c
+++ b/test/builtins/Unit/floatundisf_test.c
diff --git a/test/Unit/floatundixf_test.c b/test/builtins/Unit/floatundixf_test.c
index 1974fa01012a..1974fa01012a 100644
--- a/test/Unit/floatundixf_test.c
+++ b/test/builtins/Unit/floatundixf_test.c
diff --git a/test/builtins/Unit/floatunsitf_test.c b/test/builtins/Unit/floatunsitf_test.c
new file mode 100644
index 000000000000..1af72d246ab2
--- /dev/null
+++ b/test/builtins/Unit/floatunsitf_test.c
@@ -0,0 +1,55 @@
+//===--------------- floatunsitf_test.c - Test __floatunsitf --------------===//
+//
+// The 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 __floatunsitf for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+#if __LDBL_MANT_DIG__ == 113
+
+#include "fp_test.h"
+
+long double __floatunsitf(unsigned int a);
+
+int test__floatunsitf(unsigned int a, uint64_t expectedHi, uint64_t expectedLo)
+{
+ long double x = __floatunsitf(a);
+ int ret = compareResultLD(x, expectedHi, expectedLo);
+
+ if (ret){
+ printf("error in test__floatunsitf(%u) = %.20Lf, "
+ "expected %.20Lf\n", a, x, fromRep128(expectedHi, expectedLo));
+ }
+ return ret;
+}
+
+char assumption_1[sizeof(long double) * CHAR_BIT == 128] = {0};
+
+#endif
+
+int main()
+{
+#if __LDBL_MANT_DIG__ == 113
+ if (test__floatunsitf(0x7fffffff, UINT64_C(0x401dfffffffc0000), UINT64_C(0x0)))
+ return 1;
+ if (test__floatunsitf(0, UINT64_C(0x0), UINT64_C(0x0)))
+ return 1;
+ if (test__floatunsitf(0xffffffff, UINT64_C(0x401efffffffe0000), UINT64_C(0x0)))
+ return 1;
+ if (test__floatunsitf(0x12345678, UINT64_C(0x401b234567800000), UINT64_C(0x0)))
+ return 1;
+
+#else
+ printf("skipped\n");
+
+#endif
+ return 0;
+}
diff --git a/test/Unit/floatunssidfvfp_test.c b/test/builtins/Unit/floatunssidfvfp_test.c
index 4883af1cf5fa..4883af1cf5fa 100644
--- a/test/Unit/floatunssidfvfp_test.c
+++ b/test/builtins/Unit/floatunssidfvfp_test.c
diff --git a/test/Unit/floatunssisfvfp_test.c b/test/builtins/Unit/floatunssisfvfp_test.c
index 917061a91b18..917061a91b18 100644
--- a/test/Unit/floatunssisfvfp_test.c
+++ b/test/builtins/Unit/floatunssisfvfp_test.c
diff --git a/test/Unit/floatuntidf_test.c b/test/builtins/Unit/floatuntidf_test.c
index caad5d435e1a..3cab027051c7 100644
--- a/test/Unit/floatuntidf_test.c
+++ b/test/builtins/Unit/floatuntidf_test.c
@@ -11,12 +11,12 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <float.h>
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: convert a to a double, rounding toward even.
// Assumption: double is a IEEE 64 bit floating point type
@@ -47,7 +47,7 @@ char assumption_3[sizeof(double)*CHAR_BIT == 64] = {0};
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
if (test__floatuntidf(0, 0.0))
return 1;
diff --git a/test/Unit/floatuntisf_test.c b/test/builtins/Unit/floatuntisf_test.c
index 85c0727ce13a..aeac3ee41e54 100644
--- a/test/Unit/floatuntisf_test.c
+++ b/test/builtins/Unit/floatuntisf_test.c
@@ -11,12 +11,12 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <float.h>
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: convert a to a float, rounding toward even.
// Assumption: float is a IEEE 32 bit floating point type
@@ -47,7 +47,7 @@ char assumption_3[sizeof(float)*CHAR_BIT == 32] = {0};
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
if (test__floatuntisf(0, 0.0F))
return 1;
diff --git a/test/Unit/floatuntixf_test.c b/test/builtins/Unit/floatuntixf_test.c
index fc7531a9c823..9c3434fdde0c 100644
--- a/test/Unit/floatuntixf_test.c
+++ b/test/builtins/Unit/floatuntixf_test.c
@@ -11,12 +11,12 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <float.h>
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: convert a to a long double, rounding toward even.
// Assumption: long double is a IEEE 80 bit floating point type padded to 128 bits
@@ -48,7 +48,7 @@ char assumption_3[sizeof(long double)*CHAR_BIT == 128] = {0};
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
if (test__floatuntixf(0, 0.0))
return 1;
diff --git a/test/builtins/Unit/fp_test.h b/test/builtins/Unit/fp_test.h
new file mode 100644
index 000000000000..da58ca989cda
--- /dev/null
+++ b/test/builtins/Unit/fp_test.h
@@ -0,0 +1,223 @@
+//===--------------------------- fp_test.h - ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines shared functions for the test.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+
+enum EXPECTED_RESULT {
+ LESS_0, LESS_EQUAL_0, EQUAL_0, GREATER_0, GREATER_EQUAL_0, NEQUAL_0
+};
+
+static inline float fromRep32(uint32_t x)
+{
+ float ret;
+ memcpy(&ret, &x, 4);
+ return ret;
+}
+
+static inline double fromRep64(uint64_t x)
+{
+ double ret;
+ memcpy(&ret, &x, 8);
+ return ret;
+}
+
+static inline long double fromRep128(uint64_t hi, uint64_t lo)
+{
+ __uint128_t x = ((__uint128_t)hi << 64) + lo;
+ long double ret;
+ memcpy(&ret, &x, 16);
+ return ret;
+}
+
+static inline uint32_t toRep32(float x)
+{
+ uint32_t ret;
+ memcpy(&ret, &x, 4);
+ return ret;
+}
+
+static inline uint64_t toRep64(double x)
+{
+ uint64_t ret;
+ memcpy(&ret, &x, 8);
+ return ret;
+}
+
+static inline __uint128_t toRep128(long double x)
+{
+ __uint128_t ret;
+ memcpy(&ret, &x, 16);
+ return ret;
+}
+
+static inline int compareResultF(float result,
+ uint32_t expected)
+{
+ uint32_t rep = toRep32(result);
+
+ if (rep == expected){
+ return 0;
+ }
+ // test other posible NaN representation(signal NaN)
+ else if (expected == 0x7fc00000U){
+ if ((rep & 0x7f800000U) == 0x7f800000U &&
+ (rep & 0x7fffffU) > 0){
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static inline int compareResultD(double result,
+ uint64_t expected)
+{
+ uint64_t rep = toRep64(result);
+
+ if (rep == expected){
+ return 0;
+ }
+ // test other posible NaN representation(signal NaN)
+ else if (expected == 0x7ff8000000000000UL){
+ if ((rep & 0x7ff0000000000000UL) == 0x7ff0000000000000UL &&
+ (rep & 0xfffffffffffffUL) > 0){
+ return 0;
+ }
+ }
+ return 1;
+}
+
+// return 0 if equal
+// use two 64-bit integers intead of one 128-bit integer
+// because 128-bit integer constant can't be assigned directly
+static inline int compareResultLD(long double result,
+ uint64_t expectedHi,
+ uint64_t expectedLo)
+{
+ __uint128_t rep = toRep128(result);
+ uint64_t hi = rep >> 64;
+ uint64_t lo = rep;
+
+ if (hi == expectedHi && lo == expectedLo){
+ return 0;
+ }
+ // test other posible NaN representation(signal NaN)
+ else if (expectedHi == 0x7fff800000000000UL && expectedLo == 0x0UL){
+ if ((hi & 0x7fff000000000000UL) == 0x7fff000000000000UL &&
+ ((hi & 0xffffffffffffUL) > 0 || lo > 0)){
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static inline int compareResultCMP(int result,
+ enum EXPECTED_RESULT expected)
+{
+ switch(expected){
+ case LESS_0:
+ if (result < 0)
+ return 0;
+ break;
+ case LESS_EQUAL_0:
+ if (result <= 0)
+ return 0;
+ break;
+ case EQUAL_0:
+ if (result == 0)
+ return 0;
+ break;
+ case NEQUAL_0:
+ if (result != 0)
+ return 0;
+ break;
+ case GREATER_EQUAL_0:
+ if (result >= 0)
+ return 0;
+ break;
+ case GREATER_0:
+ if (result > 0)
+ return 0;
+ break;
+ default:
+ return 1;
+ }
+ return 1;
+}
+
+static inline char *expectedStr(enum EXPECTED_RESULT expected)
+{
+ switch(expected){
+ case LESS_0:
+ return "<0";
+ case LESS_EQUAL_0:
+ return "<=0";
+ case EQUAL_0:
+ return "=0";
+ case NEQUAL_0:
+ return "!=0";
+ case GREATER_EQUAL_0:
+ return ">=0";
+ case GREATER_0:
+ return ">0";
+ default:
+ return "";
+ }
+ return "";
+}
+
+static inline float makeQNaN32()
+{
+ return fromRep32(0x7fc00000U);
+}
+
+static inline double makeQNaN64()
+{
+ return fromRep64(0x7ff8000000000000UL);
+}
+
+static inline long double makeQNaN128()
+{
+ return fromRep128(0x7fff800000000000UL, 0x0UL);
+}
+
+static inline float makeNaN32(uint32_t rand)
+{
+ return fromRep32(0x7f800000U | (rand & 0x7fffffU));
+}
+
+static inline double makeNaN64(uint64_t rand)
+{
+ return fromRep64(0x7ff0000000000000UL | (rand & 0xfffffffffffffUL));
+}
+
+static inline long double makeNaN128(uint64_t rand)
+{
+ return fromRep128(0x7fff000000000000UL | (rand & 0xffffffffffffUL), 0x0UL);
+}
+
+static inline float makeInf32()
+{
+ return fromRep32(0x7f800000U);
+}
+
+static inline double makeInf64()
+{
+ return fromRep64(0x7ff0000000000000UL);
+}
+
+static inline long double makeInf128()
+{
+ return fromRep128(0x7fff000000000000UL, 0x0UL);
+}
diff --git a/test/Unit/gcc_personality_test.c b/test/builtins/Unit/gcc_personality_test.c
index f9598c697eb6..f9598c697eb6 100644
--- a/test/Unit/gcc_personality_test.c
+++ b/test/builtins/Unit/gcc_personality_test.c
diff --git a/test/Unit/gcc_personality_test_helper.cxx b/test/builtins/Unit/gcc_personality_test_helper.cxx
index 7d1ddfb5d960..7d1ddfb5d960 100644
--- a/test/Unit/gcc_personality_test_helper.cxx
+++ b/test/builtins/Unit/gcc_personality_test_helper.cxx
diff --git a/test/Unit/gedf2vfp_test.c b/test/builtins/Unit/gedf2vfp_test.c
index e280ce0780a5..e280ce0780a5 100644
--- a/test/Unit/gedf2vfp_test.c
+++ b/test/builtins/Unit/gedf2vfp_test.c
diff --git a/test/Unit/gesf2vfp_test.c b/test/builtins/Unit/gesf2vfp_test.c
index aa53eb739979..aa53eb739979 100644
--- a/test/Unit/gesf2vfp_test.c
+++ b/test/builtins/Unit/gesf2vfp_test.c
diff --git a/test/builtins/Unit/getf2_test.c b/test/builtins/Unit/getf2_test.c
new file mode 100644
index 000000000000..9796b8ab845d
--- /dev/null
+++ b/test/builtins/Unit/getf2_test.c
@@ -0,0 +1,89 @@
+//===------------ getf2_test.c - Test __getf2------------------------------===//
+//
+// The 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 __getf2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+#if __LP64__ && __LDBL_MANT_DIG__ == 113
+
+#include "fp_test.h"
+
+int __getf2(long double a, long double b);
+
+int test__getf2(long double a, long double b, enum EXPECTED_RESULT expected)
+{
+ int x = __getf2(a, b);
+ int ret = compareResultCMP(x, expected);
+
+ if (ret){
+ printf("error in test__getf2(%.20Lf, %.20Lf) = %d, "
+ "expected %s\n", a, b, x, expectedStr(expected));
+ }
+ return ret;
+}
+
+char assumption_1[sizeof(long double) * CHAR_BIT == 128] = {0};
+
+#endif
+
+int main()
+{
+#if __LP64__ && __LDBL_MANT_DIG__ == 113
+ // NaN
+ if (test__getf2(makeQNaN128(),
+ 0x1.234567890abcdef1234567890abcp+3L,
+ LESS_0))
+ return 1;
+ // <
+ // exp
+ if (test__getf2(0x1.234567890abcdef1234567890abcp-3L,
+ 0x1.234567890abcdef1234567890abcp+3L,
+ LESS_0))
+ return 1;
+ // mantissa
+ if (test__getf2(0x1.234567890abcdef1234567890abcp+3L,
+ 0x1.334567890abcdef1234567890abcp+3L,
+ LESS_0))
+ return 1;
+ // sign
+ if (test__getf2(-0x1.234567890abcdef1234567890abcp+3L,
+ 0x1.234567890abcdef1234567890abcp+3L,
+ LESS_0))
+ return 1;
+ // ==
+ if (test__getf2(0x1.234567890abcdef1234567890abcp+3L,
+ 0x1.234567890abcdef1234567890abcp+3L,
+ GREATER_EQUAL_0))
+ return 1;
+ // >
+ // exp
+ if (test__getf2(0x1.234567890abcdef1234567890abcp+3L,
+ 0x1.234567890abcdef1234567890abcp-3L,
+ GREATER_EQUAL_0))
+ return 1;
+ // mantissa
+ if (test__getf2(0x1.334567890abcdef1234567890abcp+3L,
+ 0x1.234567890abcdef1234567890abcp+3L,
+ GREATER_EQUAL_0))
+ return 1;
+ // sign
+ if (test__getf2(0x1.234567890abcdef1234567890abcp+3L,
+ -0x1.234567890abcdef1234567890abcp+3L,
+ GREATER_EQUAL_0))
+ return 1;
+
+#else
+ printf("skipped\n");
+
+#endif
+ return 0;
+}
diff --git a/test/Unit/gtdf2vfp_test.c b/test/builtins/Unit/gtdf2vfp_test.c
index fd54e0b4e59f..fd54e0b4e59f 100644
--- a/test/Unit/gtdf2vfp_test.c
+++ b/test/builtins/Unit/gtdf2vfp_test.c
diff --git a/test/Unit/gtsf2vfp_test.c b/test/builtins/Unit/gtsf2vfp_test.c
index 2f4ad99a63d6..2f4ad99a63d6 100644
--- a/test/Unit/gtsf2vfp_test.c
+++ b/test/builtins/Unit/gtsf2vfp_test.c
diff --git a/test/builtins/Unit/gttf2_test.c b/test/builtins/Unit/gttf2_test.c
new file mode 100644
index 000000000000..6508d4b978c9
--- /dev/null
+++ b/test/builtins/Unit/gttf2_test.c
@@ -0,0 +1,89 @@
+//===------------ gttf2_test.c - Test __gttf2------------------------------===//
+//
+// The 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 __gttf2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+#if __LP64__ && __LDBL_MANT_DIG__ == 113
+
+#include "fp_test.h"
+
+int __gttf2(long double a, long double b);
+
+int test__gttf2(long double a, long double b, enum EXPECTED_RESULT expected)
+{
+ int x = __gttf2(a, b);
+ int ret = compareResultCMP(x, expected);
+
+ if (ret){
+ printf("error in test__gttf2(%.20Lf, %.20Lf) = %d, "
+ "expected %s\n", a, b, x, expectedStr(expected));
+ }
+ return ret;
+}
+
+char assumption_1[sizeof(long double) * CHAR_BIT == 128] = {0};
+
+#endif
+
+int main()
+{
+#if __LP64__ && __LDBL_MANT_DIG__ == 113
+ // NaN
+ if (test__gttf2(makeQNaN128(),
+ 0x1.234567890abcdef1234567890abcp+3L,
+ LESS_EQUAL_0))
+ return 1;
+ // <
+ // exp
+ if (test__gttf2(0x1.234567890abcdef1234567890abcp-3L,
+ 0x1.234567890abcdef1234567890abcp+3L,
+ LESS_EQUAL_0))
+ return 1;
+ // mantissa
+ if (test__gttf2(0x1.234567890abcdef1234567890abcp+3L,
+ 0x1.334567890abcdef1234567890abcp+3L,
+ LESS_EQUAL_0))
+ return 1;
+ // sign
+ if (test__gttf2(-0x1.234567890abcdef1234567890abcp+3L,
+ 0x1.234567890abcdef1234567890abcp+3L,
+ LESS_EQUAL_0))
+ return 1;
+ // ==
+ if (test__gttf2(0x1.234567890abcdef1234567890abcp+3L,
+ 0x1.234567890abcdef1234567890abcp+3L,
+ LESS_EQUAL_0))
+ return 1;
+ // >
+ // exp
+ if (test__gttf2(0x1.234567890abcdef1234567890abcp+3L,
+ 0x1.234567890abcdef1234567890abcp-3L,
+ GREATER_0))
+ return 1;
+ // mantissa
+ if (test__gttf2(0x1.334567890abcdef1234567890abcp+3L,
+ 0x1.234567890abcdef1234567890abcp+3L,
+ GREATER_0))
+ return 1;
+ // sign
+ if (test__gttf2(0x1.234567890abcdef1234567890abcp+3L,
+ -0x1.234567890abcdef1234567890abcp+3L,
+ GREATER_0))
+ return 1;
+
+#else
+ printf("skipped\n");
+
+#endif
+ return 0;
+}
diff --git a/test/Unit/ledf2vfp_test.c b/test/builtins/Unit/ledf2vfp_test.c
index 5683590778c0..5683590778c0 100644
--- a/test/Unit/ledf2vfp_test.c
+++ b/test/builtins/Unit/ledf2vfp_test.c
diff --git a/test/Unit/lesf2vfp_test.c b/test/builtins/Unit/lesf2vfp_test.c
index b5c20f61e8ad..b5c20f61e8ad 100644
--- a/test/Unit/lesf2vfp_test.c
+++ b/test/builtins/Unit/lesf2vfp_test.c
diff --git a/test/builtins/Unit/letf2_test.c b/test/builtins/Unit/letf2_test.c
new file mode 100644
index 000000000000..1842e3c55620
--- /dev/null
+++ b/test/builtins/Unit/letf2_test.c
@@ -0,0 +1,89 @@
+//===------------ letf2_test.c - Test __letf2------------------------------===//
+//
+// The 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 __letf2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+#if __LP64__ && __LDBL_MANT_DIG__ == 113
+
+#include "fp_test.h"
+
+int __letf2(long double a, long double b);
+
+int test__letf2(long double a, long double b, enum EXPECTED_RESULT expected)
+{
+ int x = __letf2(a, b);
+ int ret = compareResultCMP(x, expected);
+
+ if (ret){
+ printf("error in test__letf2(%.20Lf, %.20Lf) = %d, "
+ "expected %s\n", a, b, x, expectedStr(expected));
+ }
+ return ret;
+}
+
+char assumption_1[sizeof(long double) * CHAR_BIT == 128] = {0};
+
+#endif
+
+int main()
+{
+#if __LP64__ && __LDBL_MANT_DIG__ == 113
+ // NaN
+ if (test__letf2(makeQNaN128(),
+ 0x1.234567890abcdef1234567890abcp+3L,
+ GREATER_0))
+ return 1;
+ // <
+ // exp
+ if (test__letf2(0x1.234567890abcdef1234567890abcp-3L,
+ 0x1.234567890abcdef1234567890abcp+3L,
+ LESS_EQUAL_0))
+ return 1;
+ // mantissa
+ if (test__letf2(0x1.234567890abcdef1234567890abcp+3L,
+ 0x1.334567890abcdef1234567890abcp+3L,
+ LESS_EQUAL_0))
+ return 1;
+ // sign
+ if (test__letf2(-0x1.234567890abcdef1234567890abcp+3L,
+ 0x1.234567890abcdef1234567890abcp+3L,
+ LESS_EQUAL_0))
+ return 1;
+ // ==
+ if (test__letf2(0x1.234567890abcdef1234567890abcp+3L,
+ 0x1.234567890abcdef1234567890abcp+3L,
+ LESS_EQUAL_0))
+ return 1;
+ // >
+ // exp
+ if (test__letf2(0x1.234567890abcdef1234567890abcp+3L,
+ 0x1.234567890abcdef1234567890abcp-3L,
+ GREATER_0))
+ return 1;
+ // mantissa
+ if (test__letf2(0x1.334567890abcdef1234567890abcp+3L,
+ 0x1.234567890abcdef1234567890abcp+3L,
+ GREATER_0))
+ return 1;
+ // sign
+ if (test__letf2(0x1.234567890abcdef1234567890abcp+3L,
+ -0x1.234567890abcdef1234567890abcp+3L,
+ GREATER_0))
+ return 1;
+
+#else
+ printf("skipped\n");
+
+#endif
+ return 0;
+}
diff --git a/test/Unit/lshrdi3_test.c b/test/builtins/Unit/lshrdi3_test.c
index ffc6a69d0e9f..ffc6a69d0e9f 100644
--- a/test/Unit/lshrdi3_test.c
+++ b/test/builtins/Unit/lshrdi3_test.c
diff --git a/test/Unit/lshrti3_test.c b/test/builtins/Unit/lshrti3_test.c
index f266b54f63c0..3f33c089cd62 100644
--- a/test/Unit/lshrti3_test.c
+++ b/test/builtins/Unit/lshrti3_test.c
@@ -11,11 +11,11 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: logical a >> b
// Precondition: 0 <= b < bits_in_dword
@@ -47,7 +47,7 @@ char assumption_1[sizeof(ti_int) == 2*sizeof(di_int)] = {0};
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
if (test__lshrti3(make_ti(0xFEDCBA9876543215LL, 0xFEDCBA9876543215LL), 0,
make_ti(0xFEDCBA9876543215LL, 0xFEDCBA9876543215LL)))
return 1;
diff --git a/test/Unit/ltdf2vfp_test.c b/test/builtins/Unit/ltdf2vfp_test.c
index 7319397c5e4d..7319397c5e4d 100644
--- a/test/Unit/ltdf2vfp_test.c
+++ b/test/builtins/Unit/ltdf2vfp_test.c
diff --git a/test/Unit/ltsf2vfp_test.c b/test/builtins/Unit/ltsf2vfp_test.c
index 2d920c959326..2d920c959326 100644
--- a/test/Unit/ltsf2vfp_test.c
+++ b/test/builtins/Unit/ltsf2vfp_test.c
diff --git a/test/builtins/Unit/lttf2_test.c b/test/builtins/Unit/lttf2_test.c
new file mode 100644
index 000000000000..e8f9dc17c6f7
--- /dev/null
+++ b/test/builtins/Unit/lttf2_test.c
@@ -0,0 +1,89 @@
+//===------------ lttf2_test.c - Test __lttf2------------------------------===//
+//
+// The 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 __lttf2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+#if __LP64__ && __LDBL_MANT_DIG__ == 113
+
+#include "fp_test.h"
+
+int __lttf2(long double a, long double b);
+
+int test__lttf2(long double a, long double b, enum EXPECTED_RESULT expected)
+{
+ int x = __lttf2(a, b);
+ int ret = compareResultCMP(x, expected);
+
+ if (ret){
+ printf("error in test__lttf2(%.20Lf, %.20Lf) = %d, "
+ "expected %s\n", a, b, x, expectedStr(expected));
+ }
+ return ret;
+}
+
+char assumption_1[sizeof(long double) * CHAR_BIT == 128] = {0};
+
+#endif
+
+int main()
+{
+#if __LP64__ && __LDBL_MANT_DIG__ == 113
+ // NaN
+ if (test__lttf2(makeQNaN128(),
+ 0x1.234567890abcdef1234567890abcp+3L,
+ GREATER_EQUAL_0))
+ return 1;
+ // <
+ // exp
+ if (test__lttf2(0x1.234567890abcdef1234567890abcp-3L,
+ 0x1.234567890abcdef1234567890abcp+3L,
+ LESS_0))
+ return 1;
+ // mantissa
+ if (test__lttf2(0x1.234567890abcdef1234567890abcp+3L,
+ 0x1.334567890abcdef1234567890abcp+3L,
+ LESS_0))
+ return 1;
+ // sign
+ if (test__lttf2(-0x1.234567890abcdef1234567890abcp+3L,
+ 0x1.234567890abcdef1234567890abcp+3L,
+ LESS_0))
+ return 1;
+ // ==
+ if (test__lttf2(0x1.234567890abcdef1234567890abcp+3L,
+ 0x1.234567890abcdef1234567890abcp+3L,
+ GREATER_EQUAL_0))
+ return 1;
+ // >
+ // exp
+ if (test__lttf2(0x1.234567890abcdef1234567890abcp+3L,
+ 0x1.234567890abcdef1234567890abcp-3L,
+ GREATER_EQUAL_0))
+ return 1;
+ // mantissa
+ if (test__lttf2(0x1.334567890abcdef1234567890abcp+3L,
+ 0x1.234567890abcdef1234567890abcp+3L,
+ GREATER_EQUAL_0))
+ return 1;
+ // sign
+ if (test__lttf2(0x1.234567890abcdef1234567890abcp+3L,
+ -0x1.234567890abcdef1234567890abcp+3L,
+ GREATER_EQUAL_0))
+ return 1;
+
+#else
+ printf("skipped\n");
+
+#endif
+ return 0;
+}
diff --git a/test/Unit/moddi3_test.c b/test/builtins/Unit/moddi3_test.c
index 9f6801d6f41b..9f6801d6f41b 100644
--- a/test/Unit/moddi3_test.c
+++ b/test/builtins/Unit/moddi3_test.c
diff --git a/test/Unit/modsi3_test.c b/test/builtins/Unit/modsi3_test.c
index 52ec9a0ae36b..52ec9a0ae36b 100644
--- a/test/Unit/modsi3_test.c
+++ b/test/builtins/Unit/modsi3_test.c
diff --git a/test/Unit/modti3_test.c b/test/builtins/Unit/modti3_test.c
index bd05c7237d2e..ba9f9804dfca 100644
--- a/test/Unit/modti3_test.c
+++ b/test/builtins/Unit/modti3_test.c
@@ -11,11 +11,11 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: a % b
ti_int __modti3(ti_int a, ti_int b);
@@ -47,7 +47,7 @@ char assumption_1[sizeof(ti_int) == 2*sizeof(di_int)] = {0};
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
if (test__modti3(0, 1, 0))
return 1;
if (test__modti3(0, -1, 0))
diff --git a/test/Unit/muldc3_test.c b/test/builtins/Unit/muldc3_test.c
index 112b6120358a..112b6120358a 100644
--- a/test/Unit/muldc3_test.c
+++ b/test/builtins/Unit/muldc3_test.c
diff --git a/test/Unit/muldf3vfp_test.c b/test/builtins/Unit/muldf3vfp_test.c
index 73454bf290aa..73454bf290aa 100644
--- a/test/Unit/muldf3vfp_test.c
+++ b/test/builtins/Unit/muldf3vfp_test.c
diff --git a/test/Unit/muldi3_test.c b/test/builtins/Unit/muldi3_test.c
index 83b525592645..83b525592645 100644
--- a/test/Unit/muldi3_test.c
+++ b/test/builtins/Unit/muldi3_test.c
diff --git a/test/Unit/mulodi4_test.c b/test/builtins/Unit/mulodi4_test.c
index 10a0eaac61f9..10a0eaac61f9 100644
--- a/test/Unit/mulodi4_test.c
+++ b/test/builtins/Unit/mulodi4_test.c
diff --git a/test/Unit/mulosi4_test.c b/test/builtins/Unit/mulosi4_test.c
index fc509db2c178..fc509db2c178 100644
--- a/test/Unit/mulosi4_test.c
+++ b/test/builtins/Unit/mulosi4_test.c
diff --git a/test/Unit/muloti4_test.c b/test/builtins/Unit/muloti4_test.c
index 44abddf26baf..95439a4197a3 100644
--- a/test/Unit/muloti4_test.c
+++ b/test/builtins/Unit/muloti4_test.c
@@ -11,11 +11,11 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: a * b
// Effects: sets overflow if a * b overflows
@@ -67,7 +67,7 @@ int test__muloti4(ti_int a, ti_int b, ti_int expected, int expected_overflow)
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
if (test__muloti4(0, 0, 0, 0))
return 1;
if (test__muloti4(0, 1, 0, 0))
diff --git a/test/Unit/mulsc3_test.c b/test/builtins/Unit/mulsc3_test.c
index 7a1b3ae0092d..7a1b3ae0092d 100644
--- a/test/Unit/mulsc3_test.c
+++ b/test/builtins/Unit/mulsc3_test.c
diff --git a/test/Unit/mulsf3vfp_test.c b/test/builtins/Unit/mulsf3vfp_test.c
index 92cf1f128497..92cf1f128497 100644
--- a/test/Unit/mulsf3vfp_test.c
+++ b/test/builtins/Unit/mulsf3vfp_test.c
diff --git a/test/Unit/multc3_test.c b/test/builtins/Unit/multc3_test.c
index f8c66c0e426f..f8c66c0e426f 100644
--- a/test/Unit/multc3_test.c
+++ b/test/builtins/Unit/multc3_test.c
diff --git a/test/builtins/Unit/multf3_test.c b/test/builtins/Unit/multf3_test.c
new file mode 100644
index 000000000000..89610056b27e
--- /dev/null
+++ b/test/builtins/Unit/multf3_test.c
@@ -0,0 +1,95 @@
+//===--------------- multf3_test.c - Test __multf3 ------------------------===//
+//
+// The 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 __multf3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+#if __LDBL_MANT_DIG__ == 113
+
+#include "fp_test.h"
+
+// Returns: a * b
+long double __multf3(long double a, long double b);
+
+int test__multf3(long double a, long double b,
+ uint64_t expectedHi, uint64_t expectedLo)
+{
+ long double x = __multf3(a, b);
+ int ret = compareResultLD(x, expectedHi, expectedLo);
+
+ if (ret){
+ printf("error in test__multf3(%.20Lf, %.20Lf) = %.20Lf, "
+ "expected %.20Lf\n", a, b, x,
+ fromRep128(expectedHi, expectedLo));
+ }
+ return ret;
+}
+
+char assumption_1[sizeof(long double) * CHAR_BIT == 128] = {0};
+
+#endif
+
+int main()
+{
+#if __LDBL_MANT_DIG__ == 113
+ // qNaN * any = qNaN
+ if (test__multf3(makeQNaN128(),
+ 0x1.23456789abcdefp+5L,
+ UINT64_C(0x7fff800000000000),
+ UINT64_C(0x0)))
+ return 1;
+ // NaN * any = NaN
+ if (test__multf3(makeNaN128(UINT64_C(0x800030000000)),
+ 0x1.23456789abcdefp+5L,
+ UINT64_C(0x7fff800000000000),
+ UINT64_C(0x0)))
+ return 1;
+ // inf * any = inf
+ if (test__multf3(makeInf128(),
+ 0x1.23456789abcdefp+5L,
+ UINT64_C(0x7fff000000000000),
+ UINT64_C(0x0)))
+ return 1;
+ // any * any
+ if (test__multf3(0x1.2eab345678439abcdefea56782346p+5L,
+ 0x1.edcb34a235253948765432134674fp-1L,
+ UINT64_C(0x400423e7f9e3c9fc),
+ UINT64_C(0xd906c2c2a85777c4)))
+ return 1;
+ if (test__multf3(0x1.353e45674d89abacc3a2ebf3ff4ffp-50L,
+ 0x1.ed8764648369535adf4be3214567fp-9L,
+ UINT64_C(0x3fc52a163c6223fc),
+ UINT64_C(0xc94c4bf0430768b4)))
+ return 1;
+ if (test__multf3(0x1.234425696abcad34a35eeffefdcbap+456L,
+ 0x451.ed98d76e5d46e5f24323dff21ffp+600L,
+ UINT64_C(0x44293a91de5e0e94),
+ UINT64_C(0xe8ed17cc2cdf64ac)))
+ return 1;
+ if (test__multf3(0x1.4356473c82a9fabf2d22ace345defp-234L,
+ 0x1.eda98765476743ab21da23d45678fp-455L,
+ UINT64_C(0x3d4f37c1a3137cae),
+ UINT64_C(0xfc6807048bc2836a)))
+ return 1;
+ // underflow
+ if (test__multf3(0x1.23456734245345p-10000L,
+ 0x1.edcba524498724p-6383L,
+ UINT64_C(0x0),
+ UINT64_C(0x0)))
+ return 1;
+
+#else
+ printf("skipped\n");
+
+#endif
+ return 0;
+}
diff --git a/test/Unit/multi3_test.c b/test/builtins/Unit/multi3_test.c
index f8c6605eb254..2ccbd06c3e7d 100644
--- a/test/Unit/multi3_test.c
+++ b/test/builtins/Unit/multi3_test.c
@@ -11,11 +11,11 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
ti_int __multi3(ti_int a, ti_int b);
int test__multi3(ti_int a, ti_int b, ti_int expected)
@@ -45,7 +45,7 @@ char assumption_1[sizeof(ti_int) == 2*sizeof(di_int)] = {0};
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
if (test__multi3(0, 0, 0))
return 1;
if (test__multi3(0, 1, 0))
diff --git a/test/Unit/mulvdi3_test.c b/test/builtins/Unit/mulvdi3_test.c
index a023bf611279..a023bf611279 100644
--- a/test/Unit/mulvdi3_test.c
+++ b/test/builtins/Unit/mulvdi3_test.c
diff --git a/test/Unit/mulvsi3_test.c b/test/builtins/Unit/mulvsi3_test.c
index 1eb53a5d5daa..1eb53a5d5daa 100644
--- a/test/Unit/mulvsi3_test.c
+++ b/test/builtins/Unit/mulvsi3_test.c
diff --git a/test/Unit/mulvti3_test.c b/test/builtins/Unit/mulvti3_test.c
index be1aa2d331c6..6336f4550e0d 100644
--- a/test/Unit/mulvti3_test.c
+++ b/test/builtins/Unit/mulvti3_test.c
@@ -11,11 +11,11 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: a * b
// Effects: aborts if a * b overflows
@@ -47,7 +47,7 @@ int test__mulvti3(ti_int a, ti_int b, ti_int expected)
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
if (test__mulvti3(0, 0, 0))
return 1;
if (test__mulvti3(0, 1, 0))
diff --git a/test/Unit/mulxc3_test.c b/test/builtins/Unit/mulxc3_test.c
index 4297c162bd8e..4297c162bd8e 100644
--- a/test/Unit/mulxc3_test.c
+++ b/test/builtins/Unit/mulxc3_test.c
diff --git a/test/Unit/nedf2vfp_test.c b/test/builtins/Unit/nedf2vfp_test.c
index 2c4404399633..2c4404399633 100644
--- a/test/Unit/nedf2vfp_test.c
+++ b/test/builtins/Unit/nedf2vfp_test.c
diff --git a/test/Unit/negdf2vfp_test.c b/test/builtins/Unit/negdf2vfp_test.c
index dc55428d6780..dc55428d6780 100644
--- a/test/Unit/negdf2vfp_test.c
+++ b/test/builtins/Unit/negdf2vfp_test.c
diff --git a/test/Unit/negdi2_test.c b/test/builtins/Unit/negdi2_test.c
index 510b3b046b56..510b3b046b56 100644
--- a/test/Unit/negdi2_test.c
+++ b/test/builtins/Unit/negdi2_test.c
diff --git a/test/Unit/negsf2vfp_test.c b/test/builtins/Unit/negsf2vfp_test.c
index ef54cee1dbee..ef54cee1dbee 100644
--- a/test/Unit/negsf2vfp_test.c
+++ b/test/builtins/Unit/negsf2vfp_test.c
diff --git a/test/Unit/negti2_test.c b/test/builtins/Unit/negti2_test.c
index 1945accfa952..a40c0c324bb2 100644
--- a/test/Unit/negti2_test.c
+++ b/test/builtins/Unit/negti2_test.c
@@ -11,11 +11,11 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: -a
ti_int __negti2(ti_int a);
@@ -44,7 +44,7 @@ char assumption_1[sizeof(ti_int) == 2*sizeof(di_int)] = {0};
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
if (test__negti2(0, 0))
return 1;
if (test__negti2(1, -1))
diff --git a/test/Unit/negvdi2_test.c b/test/builtins/Unit/negvdi2_test.c
index 9617b95ff105..9617b95ff105 100644
--- a/test/Unit/negvdi2_test.c
+++ b/test/builtins/Unit/negvdi2_test.c
diff --git a/test/Unit/negvsi2_test.c b/test/builtins/Unit/negvsi2_test.c
index 5ea0e2e86c2a..5ea0e2e86c2a 100644
--- a/test/Unit/negvsi2_test.c
+++ b/test/builtins/Unit/negvsi2_test.c
diff --git a/test/Unit/negvti2_test.c b/test/builtins/Unit/negvti2_test.c
index 772840989ad6..8126cdb5b668 100644
--- a/test/Unit/negvti2_test.c
+++ b/test/builtins/Unit/negvti2_test.c
@@ -11,11 +11,11 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: -a
// Effects: aborts if -a overflows
@@ -46,7 +46,7 @@ int test__negvti2(ti_int a)
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
if (test__negvti2(0))
return 1;
if (test__negvti2(1))
diff --git a/test/Unit/nesf2vfp_test.c b/test/builtins/Unit/nesf2vfp_test.c
index c085bf8b41fa..c085bf8b41fa 100644
--- a/test/Unit/nesf2vfp_test.c
+++ b/test/builtins/Unit/nesf2vfp_test.c
diff --git a/test/builtins/Unit/netf2_test.c b/test/builtins/Unit/netf2_test.c
new file mode 100644
index 000000000000..bbd953ab59e2
--- /dev/null
+++ b/test/builtins/Unit/netf2_test.c
@@ -0,0 +1,89 @@
+//===------------ netf2_test.c - Test __netf2------------------------------===//
+//
+// The 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 __netf2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+#if __LP64__ && __LDBL_MANT_DIG__ == 113
+
+#include "fp_test.h"
+
+int __netf2(long double a, long double b);
+
+int test__netf2(long double a, long double b, enum EXPECTED_RESULT expected)
+{
+ int x = __netf2(a, b);
+ int ret = compareResultCMP(x, expected);
+
+ if (ret){
+ printf("error in test__netf2(%.20Lf, %.20Lf) = %d, "
+ "expected %s\n", a, b, x, expectedStr(expected));
+ }
+ return ret;
+}
+
+char assumption_1[sizeof(long double) * CHAR_BIT == 128] = {0};
+
+#endif
+
+int main()
+{
+#if __LP64__ && __LDBL_MANT_DIG__ == 113
+ // NaN
+ if (test__netf2(makeQNaN128(),
+ 0x1.234567890abcdef1234567890abcp+3L,
+ NEQUAL_0))
+ return 1;
+ // <
+ // exp
+ if (test__netf2(0x1.234567890abcdef1234567890abcp-3L,
+ 0x1.234567890abcdef1234567890abcp+3L,
+ NEQUAL_0))
+ return 1;
+ // mantissa
+ if (test__netf2(0x1.234567890abcdef1234567890abcp+3L,
+ 0x1.334567890abcdef1234567890abcp+3L,
+ NEQUAL_0))
+ return 1;
+ // sign
+ if (test__netf2(-0x1.234567890abcdef1234567890abcp+3L,
+ 0x1.234567890abcdef1234567890abcp+3L,
+ NEQUAL_0))
+ return 1;
+ // ==
+ if (test__netf2(0x1.234567890abcdef1234567890abcp+3L,
+ 0x1.234567890abcdef1234567890abcp+3L,
+ EQUAL_0))
+ return 1;
+ // >
+ // exp
+ if (test__netf2(0x1.234567890abcdef1234567890abcp+3L,
+ 0x1.234567890abcdef1234567890abcp-3L,
+ NEQUAL_0))
+ return 1;
+ // mantissa
+ if (test__netf2(0x1.334567890abcdef1234567890abcp+3L,
+ 0x1.234567890abcdef1234567890abcp+3L,
+ NEQUAL_0))
+ return 1;
+ // sign
+ if (test__netf2(0x1.234567890abcdef1234567890abcp+3L,
+ -0x1.234567890abcdef1234567890abcp+3L,
+ NEQUAL_0))
+ return 1;
+
+#else
+ printf("skipped\n");
+
+#endif
+ return 0;
+}
diff --git a/test/Unit/paritydi2_test.c b/test/builtins/Unit/paritydi2_test.c
index 5360e374d439..5360e374d439 100644
--- a/test/Unit/paritydi2_test.c
+++ b/test/builtins/Unit/paritydi2_test.c
diff --git a/test/Unit/paritysi2_test.c b/test/builtins/Unit/paritysi2_test.c
index 3ea8473aad5c..3ea8473aad5c 100644
--- a/test/Unit/paritysi2_test.c
+++ b/test/builtins/Unit/paritysi2_test.c
diff --git a/test/Unit/parityti2_test.c b/test/builtins/Unit/parityti2_test.c
index ac67b35669a7..8f065b953d22 100644
--- a/test/Unit/parityti2_test.c
+++ b/test/builtins/Unit/parityti2_test.c
@@ -11,12 +11,12 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <stdio.h>
#include <stdlib.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: 1 if number of bits is odd else returns 0
si_int __parityti2(ti_int a);
@@ -50,7 +50,7 @@ char assumption_2[sizeof(di_int)*CHAR_BIT == 64] = {0};
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
int i;
for (i = 0; i < 10000; ++i)
if (test__parityti2(((ti_int)rand() << 96) + ((ti_int)rand() << 64) +
diff --git a/test/Unit/popcountdi2_test.c b/test/builtins/Unit/popcountdi2_test.c
index 4c5611796434..4c5611796434 100644
--- a/test/Unit/popcountdi2_test.c
+++ b/test/builtins/Unit/popcountdi2_test.c
diff --git a/test/Unit/popcountsi2_test.c b/test/builtins/Unit/popcountsi2_test.c
index d0a05c45e544..d0a05c45e544 100644
--- a/test/Unit/popcountsi2_test.c
+++ b/test/builtins/Unit/popcountsi2_test.c
diff --git a/test/Unit/popcountti2_test.c b/test/builtins/Unit/popcountti2_test.c
index 1b94a0c6aa51..d17e03afd665 100644
--- a/test/Unit/popcountti2_test.c
+++ b/test/builtins/Unit/popcountti2_test.c
@@ -11,12 +11,12 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <stdio.h>
#include <stdlib.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: count of 1 bits
si_int __popcountti2(ti_int a);
@@ -50,7 +50,7 @@ char assumption_2[sizeof(di_int)*CHAR_BIT == 64] = {0};
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
if (test__popcountti2(0))
return 1;
if (test__popcountti2(1))
diff --git a/test/Unit/powidf2_test.c b/test/builtins/Unit/powidf2_test.c
index 2abc84de7676..2abc84de7676 100644
--- a/test/Unit/powidf2_test.c
+++ b/test/builtins/Unit/powidf2_test.c
diff --git a/test/Unit/powisf2_test.c b/test/builtins/Unit/powisf2_test.c
index 98409f432e66..98409f432e66 100644
--- a/test/Unit/powisf2_test.c
+++ b/test/builtins/Unit/powisf2_test.c
diff --git a/test/Unit/powitf2_test.c b/test/builtins/Unit/powitf2_test.c
index 817cb1130dee..817cb1130dee 100644
--- a/test/Unit/powitf2_test.c
+++ b/test/builtins/Unit/powitf2_test.c
diff --git a/test/Unit/powixf2_test.c b/test/builtins/Unit/powixf2_test.c
index 201870b37f15..201870b37f15 100644
--- a/test/Unit/powixf2_test.c
+++ b/test/builtins/Unit/powixf2_test.c
diff --git a/test/Unit/ppc/DD.h b/test/builtins/Unit/ppc/DD.h
index fd62dae16b22..fd62dae16b22 100644
--- a/test/Unit/ppc/DD.h
+++ b/test/builtins/Unit/ppc/DD.h
diff --git a/test/Unit/ppc/fixtfdi_test.c b/test/builtins/Unit/ppc/fixtfdi_test.c
index b4865fb8e6e9..b4865fb8e6e9 100644
--- a/test/Unit/ppc/fixtfdi_test.c
+++ b/test/builtins/Unit/ppc/fixtfdi_test.c
diff --git a/test/Unit/ppc/floatditf_test.c b/test/builtins/Unit/ppc/floatditf_test.c
index 578260aeddc4..578260aeddc4 100644
--- a/test/Unit/ppc/floatditf_test.c
+++ b/test/builtins/Unit/ppc/floatditf_test.c
diff --git a/test/Unit/ppc/floatditf_test.h b/test/builtins/Unit/ppc/floatditf_test.h
index 8b47e1731dcc..8b47e1731dcc 100644
--- a/test/Unit/ppc/floatditf_test.h
+++ b/test/builtins/Unit/ppc/floatditf_test.h
diff --git a/test/Unit/ppc/floatunditf_test.c b/test/builtins/Unit/ppc/floatunditf_test.c
index 68390d197229..68390d197229 100644
--- a/test/Unit/ppc/floatunditf_test.c
+++ b/test/builtins/Unit/ppc/floatunditf_test.c
diff --git a/test/Unit/ppc/floatunditf_test.h b/test/builtins/Unit/ppc/floatunditf_test.h
index 4a42e973b69d..4a42e973b69d 100644
--- a/test/Unit/ppc/floatunditf_test.h
+++ b/test/builtins/Unit/ppc/floatunditf_test.h
diff --git a/test/Unit/ppc/qadd_test.c b/test/builtins/Unit/ppc/qadd_test.c
index 6d4ca93c2698..6d4ca93c2698 100644
--- a/test/Unit/ppc/qadd_test.c
+++ b/test/builtins/Unit/ppc/qadd_test.c
diff --git a/test/Unit/ppc/qdiv_test.c b/test/builtins/Unit/ppc/qdiv_test.c
index 8e4e75a50ad6..8e4e75a50ad6 100644
--- a/test/Unit/ppc/qdiv_test.c
+++ b/test/builtins/Unit/ppc/qdiv_test.c
diff --git a/test/Unit/ppc/qmul_test.c b/test/builtins/Unit/ppc/qmul_test.c
index fc5b46d3366a..fc5b46d3366a 100644
--- a/test/Unit/ppc/qmul_test.c
+++ b/test/builtins/Unit/ppc/qmul_test.c
diff --git a/test/Unit/ppc/qsub_test.c b/test/builtins/Unit/ppc/qsub_test.c
index 43bc7f4a854a..43bc7f4a854a 100644
--- a/test/Unit/ppc/qsub_test.c
+++ b/test/builtins/Unit/ppc/qsub_test.c
diff --git a/test/Unit/ppc/test b/test/builtins/Unit/ppc/test
index 96e06320dbe2..96e06320dbe2 100755
--- a/test/Unit/ppc/test
+++ b/test/builtins/Unit/ppc/test
diff --git a/test/Unit/subdf3vfp_test.c b/test/builtins/Unit/subdf3vfp_test.c
index 86d6f2fef22b..86d6f2fef22b 100644
--- a/test/Unit/subdf3vfp_test.c
+++ b/test/builtins/Unit/subdf3vfp_test.c
diff --git a/test/Unit/subsf3vfp_test.c b/test/builtins/Unit/subsf3vfp_test.c
index 223e7f8f3936..223e7f8f3936 100644
--- a/test/Unit/subsf3vfp_test.c
+++ b/test/builtins/Unit/subsf3vfp_test.c
diff --git a/test/builtins/Unit/subtf3_test.c b/test/builtins/Unit/subtf3_test.c
new file mode 100644
index 000000000000..2ab249a994c3
--- /dev/null
+++ b/test/builtins/Unit/subtf3_test.c
@@ -0,0 +1,74 @@
+//===--------------- subtf3_test.c - Test __subtf3 ------------------------===//
+//
+// The 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 __subtf3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+#if __LDBL_MANT_DIG__ == 113
+
+#include "fp_test.h"
+
+// Returns: a - b
+long double __subtf3(long double a, long double b);
+
+int test__subtf3(long double a, long double b,
+ uint64_t expectedHi, uint64_t expectedLo)
+{
+ long double x = __subtf3(a, b);
+ int ret = compareResultLD(x, expectedHi, expectedLo);
+
+ if (ret){
+ printf("error in test__subtf3(%.20Lf, %.20Lf) = %.20Lf, "
+ "expected %.20Lf\n", a, b, x,
+ fromRep128(expectedHi, expectedLo));
+ }
+ return ret;
+}
+
+char assumption_1[sizeof(long double) * CHAR_BIT == 128] = {0};
+
+#endif
+
+int main()
+{
+#if __LDBL_MANT_DIG__ == 113
+ // qNaN - any = qNaN
+ if (test__subtf3(makeQNaN128(),
+ 0x1.23456789abcdefp+5L,
+ UINT64_C(0x7fff800000000000),
+ UINT64_C(0x0)))
+ return 1;
+ // NaN - any = NaN
+ if (test__subtf3(makeNaN128(UINT64_C(0x800030000000)),
+ 0x1.23456789abcdefp+5L,
+ UINT64_C(0x7fff800000000000),
+ UINT64_C(0x0)))
+ return 1;
+ // inf - any = inf
+ if (test__subtf3(makeInf128(),
+ 0x1.23456789abcdefp+5L,
+ UINT64_C(0x7fff000000000000),
+ UINT64_C(0x0)))
+ return 1;
+ // any - any
+ if (test__subtf3(0x1.234567829a3bcdef5678ade36734p+5L,
+ 0x1.ee9d7c52354a6936ab8d7654321fp-1L,
+ UINT64_C(0x40041b8af1915166),
+ UINT64_C(0xa44a7bca780a166c)))
+ return 1;
+
+#else
+ printf("skipped\n");
+
+#endif
+ return 0;
+}
diff --git a/test/Unit/subvdi3_test.c b/test/builtins/Unit/subvdi3_test.c
index 0fb8f5156896..0fb8f5156896 100644
--- a/test/Unit/subvdi3_test.c
+++ b/test/builtins/Unit/subvdi3_test.c
diff --git a/test/Unit/subvsi3_test.c b/test/builtins/Unit/subvsi3_test.c
index 14e6ce193904..14e6ce193904 100644
--- a/test/Unit/subvsi3_test.c
+++ b/test/builtins/Unit/subvsi3_test.c
diff --git a/test/Unit/subvti3_test.c b/test/builtins/Unit/subvti3_test.c
index 6176bdfda97a..b2c225c3a7f4 100644
--- a/test/Unit/subvti3_test.c
+++ b/test/builtins/Unit/subvti3_test.c
@@ -11,12 +11,12 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <stdio.h>
#include <stdlib.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: a - b
// Effects: aborts if a - b overflows
@@ -49,7 +49,7 @@ int test__subvti3(ti_int a, ti_int b)
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
// test__subvti3(make_ti(0x8000000000000000LL, 0), 1); // should abort
// test__subvti3(0, make_ti(0x8000000000000000LL, 0)); // should abort
// test__subvti3(1, make_ti(0x8000000000000000LL, 0)); // should abort
diff --git a/test/Unit/test b/test/builtins/Unit/test
index e2a39a92ed2f..e2a39a92ed2f 100755
--- a/test/Unit/test
+++ b/test/builtins/Unit/test
diff --git a/test/Unit/trampoline_setup_test.c b/test/builtins/Unit/trampoline_setup_test.c
index dc30fb6df60a..dc30fb6df60a 100644
--- a/test/Unit/trampoline_setup_test.c
+++ b/test/builtins/Unit/trampoline_setup_test.c
diff --git a/test/Unit/truncdfsf2vfp_test.c b/test/builtins/Unit/truncdfsf2vfp_test.c
index afc7868b0de0..afc7868b0de0 100644
--- a/test/Unit/truncdfsf2vfp_test.c
+++ b/test/builtins/Unit/truncdfsf2vfp_test.c
diff --git a/test/builtins/Unit/trunctfdf2_test.c b/test/builtins/Unit/trunctfdf2_test.c
new file mode 100644
index 000000000000..46855e31bb5e
--- /dev/null
+++ b/test/builtins/Unit/trunctfdf2_test.c
@@ -0,0 +1,76 @@
+//===-------------- trunctfdf2_test.c - Test __trunctfdf2 -----------------===//
+//
+// The 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 __trunctfdf2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+#if __LDBL_MANT_DIG__ == 113
+
+#include "fp_test.h"
+
+double __trunctfdf2(long double a);
+
+int test__trunctfdf2(long double a, uint64_t expected)
+{
+ double x = __trunctfdf2(a);
+ int ret = compareResultD(x, expected);
+
+ if (ret)
+ {
+ printf("error in test__trunctfdf2(%.20Lf) = %lf, "
+ "expected %lf\n", a, x, fromRep64(expected));
+ }
+ return ret;
+}
+
+char assumption_1[sizeof(long double) * CHAR_BIT == 128] = {0};
+
+#endif
+
+int main()
+{
+#if __LDBL_MANT_DIG__ == 113
+ // qNaN
+ if (test__trunctfdf2(makeQNaN128(),
+ UINT64_C(0x7ff8000000000000)))
+ return 1;
+ // NaN
+ if (test__trunctfdf2(makeNaN128(UINT64_C(0x810000000000)),
+ UINT64_C(0x7ff8100000000000)))
+ return 1;
+ // inf
+ if (test__trunctfdf2(makeInf128(),
+ UINT64_C(0x7ff0000000000000)))
+ return 1;
+ // zero
+ if (test__trunctfdf2(0.0L, UINT64_C(0x0)))
+ return 1;
+
+ if (test__trunctfdf2(0x1.af23456789bbaaab347645365cdep+5L,
+ UINT64_C(0x404af23456789bbb)))
+ return 1;
+ if (test__trunctfdf2(0x1.dedafcff354b6ae9758763545432p-9L,
+ UINT64_C(0x3f6dedafcff354b7)))
+ return 1;
+ if (test__trunctfdf2(0x1.2f34dd5f437e849b4baab754cdefp+4534L,
+ UINT64_C(0x7ff0000000000000)))
+ return 1;
+ if (test__trunctfdf2(0x1.edcbff8ad76ab5bf46463233214fp-435L,
+ UINT64_C(0x24cedcbff8ad76ab)))
+ return 1;
+
+#else
+ printf("skipped\n");
+
+#endif
+ return 0;
+}
diff --git a/test/builtins/Unit/trunctfsf2_test.c b/test/builtins/Unit/trunctfsf2_test.c
new file mode 100644
index 000000000000..44e7fd1827fe
--- /dev/null
+++ b/test/builtins/Unit/trunctfsf2_test.c
@@ -0,0 +1,75 @@
+//===--------------- trunctfsf2_test.c - Test __trunctfsf2 ----------------===//
+//
+// The 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 __trunctfsf2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+#if __LDBL_MANT_DIG__ == 113
+
+#include "fp_test.h"
+
+float __trunctfsf2(long double a);
+
+int test__trunctfsf2(long double a, uint32_t expected)
+{
+ float x = __trunctfsf2(a);
+ int ret = compareResultF(x, expected);
+
+ if (ret){
+ printf("error in test__trunctfsf2(%.20Lf) = %f, "
+ "expected %f\n", a, x, fromRep32(expected));
+ }
+ return ret;
+}
+
+char assumption_1[sizeof(long double) * CHAR_BIT == 128] = {0};
+
+#endif
+
+int main()
+{
+#if __LDBL_MANT_DIG__ == 113
+ // qNaN
+ if (test__trunctfsf2(makeQNaN128(),
+ UINT32_C(0x7fc00000)))
+ return 1;
+ // NaN
+ if (test__trunctfsf2(makeNaN128(UINT64_C(0x810000000000)),
+ UINT32_C(0x7fc08000)))
+ return 1;
+ // inf
+ if (test__trunctfsf2(makeInf128(),
+ UINT32_C(0x7f800000)))
+ return 1;
+ // zero
+ if (test__trunctfsf2(0.0L, UINT32_C(0x0)))
+ return 1;
+
+ if (test__trunctfsf2(0x1.23a2abb4a2ddee355f36789abcdep+5L,
+ UINT32_C(0x4211d156)))
+ return 1;
+ if (test__trunctfsf2(0x1.e3d3c45bd3abfd98b76a54cc321fp-9L,
+ UINT32_C(0x3b71e9e2)))
+ return 1;
+ if (test__trunctfsf2(0x1.234eebb5faa678f4488693abcdefp+4534L,
+ UINT32_C(0x7f800000)))
+ return 1;
+ if (test__trunctfsf2(0x1.edcba9bb8c76a5a43dd21f334634p-435L,
+ UINT32_C(0x0)))
+ return 1;
+
+#else
+ printf("skipped\n");
+
+#endif
+ return 0;
+}
diff --git a/test/Unit/ucmpdi2_test.c b/test/builtins/Unit/ucmpdi2_test.c
index 22059077c795..22059077c795 100644
--- a/test/Unit/ucmpdi2_test.c
+++ b/test/builtins/Unit/ucmpdi2_test.c
diff --git a/test/Unit/ucmpti2_test.c b/test/builtins/Unit/ucmpti2_test.c
index 55f820b89f2c..0713da8971af 100644
--- a/test/Unit/ucmpti2_test.c
+++ b/test/builtins/Unit/ucmpti2_test.c
@@ -11,11 +11,11 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: if (a < b) returns 0
// if (a == b) returns 1
// if (a > b) returns 2
@@ -42,7 +42,7 @@ int test__ucmpti2(tu_int a, tu_int b, si_int expected)
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
if (test__ucmpti2(0, 0, 1))
return 1;
if (test__ucmpti2(1, 1, 1))
diff --git a/test/Unit/udivdi3_test.c b/test/builtins/Unit/udivdi3_test.c
index 24843f8bde6a..24843f8bde6a 100644
--- a/test/Unit/udivdi3_test.c
+++ b/test/builtins/Unit/udivdi3_test.c
diff --git a/test/Unit/udivmoddi4_test.c b/test/builtins/Unit/udivmoddi4_test.c
index 43bf1a11f348..43bf1a11f348 100644
--- a/test/Unit/udivmoddi4_test.c
+++ b/test/builtins/Unit/udivmoddi4_test.c
diff --git a/test/Unit/udivmodsi4_test.c b/test/builtins/Unit/udivmodsi4_test.c
index d734cd1fdf71..d734cd1fdf71 100644
--- a/test/Unit/udivmodsi4_test.c
+++ b/test/builtins/Unit/udivmodsi4_test.c
diff --git a/test/Unit/udivmodti4_test.c b/test/builtins/Unit/udivmodti4_test.c
index e0cae35ea7ae..751aa868325f 100644
--- a/test/Unit/udivmodti4_test.c
+++ b/test/builtins/Unit/udivmodti4_test.c
@@ -11,11 +11,11 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
// Effects: if rem != 0, *rem = a % b
// Returns: a / b
@@ -65339,7 +65339,7 @@ tu_int tests[][4] =
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
const unsigned N = sizeof(tests) / sizeof(tests[0]);
unsigned i;
for (i = 0; i < N; ++i)
diff --git a/test/Unit/udivsi3_test.c b/test/builtins/Unit/udivsi3_test.c
index 325e4e6e8859..325e4e6e8859 100644
--- a/test/Unit/udivsi3_test.c
+++ b/test/builtins/Unit/udivsi3_test.c
diff --git a/test/Unit/udivti3_test.c b/test/builtins/Unit/udivti3_test.c
index 09e0e1cf70d9..af5aad9a391d 100644
--- a/test/Unit/udivti3_test.c
+++ b/test/builtins/Unit/udivti3_test.c
@@ -11,11 +11,11 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: a / b
tu_int __udivti3(tu_int a, tu_int b);
@@ -45,7 +45,7 @@ int test__udivti3(tu_int a, tu_int b, tu_int expected_q)
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
if (test__udivti3(0, 1, 0))
return 1;
if (test__udivti3(2, 1, 2))
diff --git a/test/Unit/umoddi3_test.c b/test/builtins/Unit/umoddi3_test.c
index a8f39b41550d..a8f39b41550d 100644
--- a/test/Unit/umoddi3_test.c
+++ b/test/builtins/Unit/umoddi3_test.c
diff --git a/test/Unit/umodsi3_test.c b/test/builtins/Unit/umodsi3_test.c
index 66da695ffd96..66da695ffd96 100644
--- a/test/Unit/umodsi3_test.c
+++ b/test/builtins/Unit/umodsi3_test.c
diff --git a/test/Unit/umodti3_test.c b/test/builtins/Unit/umodti3_test.c
index 5eac2d834fbf..93b556ccaa21 100644
--- a/test/Unit/umodti3_test.c
+++ b/test/builtins/Unit/umodti3_test.c
@@ -11,11 +11,11 @@
//
//===----------------------------------------------------------------------===//
-#if __x86_64
-
#include "int_lib.h"
#include <stdio.h>
+#ifdef CRT_HAS_128BIT
+
// Returns: a % b
tu_int __umodti3(tu_int a, tu_int b);
@@ -45,7 +45,7 @@ int test__umodti3(tu_int a, tu_int b, tu_int expected_r)
int main()
{
-#if __x86_64
+#ifdef CRT_HAS_128BIT
if (test__umodti3(0, 1, 0))
return 1;
if (test__umodti3(2, 1, 0))
diff --git a/test/Unit/unorddf2vfp_test.c b/test/builtins/Unit/unorddf2vfp_test.c
index d49d567896ae..d49d567896ae 100644
--- a/test/Unit/unorddf2vfp_test.c
+++ b/test/builtins/Unit/unorddf2vfp_test.c
diff --git a/test/Unit/unordsf2vfp_test.c b/test/builtins/Unit/unordsf2vfp_test.c
index 3cadc81c708b..3cadc81c708b 100644
--- a/test/Unit/unordsf2vfp_test.c
+++ b/test/builtins/Unit/unordsf2vfp_test.c
diff --git a/test/builtins/Unit/unordtf2_test.c b/test/builtins/Unit/unordtf2_test.c
new file mode 100644
index 000000000000..114cd8cb38a7
--- /dev/null
+++ b/test/builtins/Unit/unordtf2_test.c
@@ -0,0 +1,65 @@
+//===------------ unordtf2_test.c - Test __unordtf2------------------------===//
+//
+// The 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 __unordtf2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+#if __LP64__ && __LDBL_MANT_DIG__ == 113
+
+#include "fp_test.h"
+
+int __unordtf2(long double a, long double b);
+
+int test__unordtf2(long double a, long double b, enum EXPECTED_RESULT expected)
+{
+ int x = __unordtf2(a, b);
+ int ret = compareResultCMP(x, expected);
+
+ if (ret){
+ printf("error in test__unordtf2(%.20Lf, %.20Lf) = %d, "
+ "expected %s\n", a, b, x, expectedStr(expected));
+ }
+ return ret;
+}
+
+char assumption_1[sizeof(long double) * CHAR_BIT == 128] = {0};
+
+#endif
+
+int main()
+{
+#if __LP64__ && __LDBL_MANT_DIG__ == 113
+ // NaN
+ if (test__unordtf2(makeQNaN128(),
+ 0x1.234567890abcdef1234567890abcp+3L,
+ NEQUAL_0))
+ return 1;
+ // other
+ if (test__unordtf2(0x1.234567890abcdef1234567890abcp+3L,
+ 0x1.334567890abcdef1234567890abcp+3L,
+ EQUAL_0))
+ return 1;
+ if (test__unordtf2(0x1.234567890abcdef1234567890abcp+3L,
+ 0x1.234567890abcdef1234567890abcp+3L,
+ EQUAL_0))
+ return 1;
+ if (test__unordtf2(0x1.234567890abcdef1234567890abcp+3L,
+ 0x1.234567890abcdef1234567890abcp-3L,
+ EQUAL_0))
+ return 1;
+
+#else
+ printf("skipped\n");
+
+#endif
+ return 0;
+}
diff --git a/test/timing/ashldi3.c b/test/builtins/timing/ashldi3.c
index 0d7378d4167a..0d7378d4167a 100644
--- a/test/timing/ashldi3.c
+++ b/test/builtins/timing/ashldi3.c
diff --git a/test/timing/ashrdi3.c b/test/builtins/timing/ashrdi3.c
index 84e11f7fe354..84e11f7fe354 100644
--- a/test/timing/ashrdi3.c
+++ b/test/builtins/timing/ashrdi3.c
diff --git a/test/timing/divdi3.c b/test/builtins/timing/divdi3.c
index 37937aab624b..37937aab624b 100644
--- a/test/timing/divdi3.c
+++ b/test/builtins/timing/divdi3.c
diff --git a/test/timing/floatdidf.c b/test/builtins/timing/floatdidf.c
index 2c970d4df4c9..2c970d4df4c9 100644
--- a/test/timing/floatdidf.c
+++ b/test/builtins/timing/floatdidf.c
diff --git a/test/timing/floatdisf.c b/test/builtins/timing/floatdisf.c
index 801ab0aa2e60..801ab0aa2e60 100644
--- a/test/timing/floatdisf.c
+++ b/test/builtins/timing/floatdisf.c
diff --git a/test/timing/floatdixf.c b/test/builtins/timing/floatdixf.c
index b646e3c1b746..b646e3c1b746 100644
--- a/test/timing/floatdixf.c
+++ b/test/builtins/timing/floatdixf.c
diff --git a/test/timing/floatundidf.c b/test/builtins/timing/floatundidf.c
index 25c02bd2eab0..25c02bd2eab0 100644
--- a/test/timing/floatundidf.c
+++ b/test/builtins/timing/floatundidf.c
diff --git a/test/timing/floatundisf.c b/test/builtins/timing/floatundisf.c
index ec8f3beb9c25..ec8f3beb9c25 100644
--- a/test/timing/floatundisf.c
+++ b/test/builtins/timing/floatundisf.c
diff --git a/test/timing/floatundixf.c b/test/builtins/timing/floatundixf.c
index 46733eb2606b..46733eb2606b 100644
--- a/test/timing/floatundixf.c
+++ b/test/builtins/timing/floatundixf.c
diff --git a/test/timing/lshrdi3.c b/test/builtins/timing/lshrdi3.c
index b474cf3e0c38..b474cf3e0c38 100644
--- a/test/timing/lshrdi3.c
+++ b/test/builtins/timing/lshrdi3.c
diff --git a/test/timing/moddi3.c b/test/builtins/timing/moddi3.c
index 83e2441dc937..83e2441dc937 100644
--- a/test/timing/moddi3.c
+++ b/test/builtins/timing/moddi3.c
diff --git a/test/timing/modsi3.c b/test/builtins/timing/modsi3.c
index 3275b8324474..3275b8324474 100644
--- a/test/timing/modsi3.c
+++ b/test/builtins/timing/modsi3.c
diff --git a/test/timing/muldi3.c b/test/builtins/timing/muldi3.c
index 3ba3af245224..3ba3af245224 100644
--- a/test/timing/muldi3.c
+++ b/test/builtins/timing/muldi3.c
diff --git a/test/timing/negdi2.c b/test/builtins/timing/negdi2.c
index 2668eb1e831f..2668eb1e831f 100644
--- a/test/timing/negdi2.c
+++ b/test/builtins/timing/negdi2.c
diff --git a/test/timing/time b/test/builtins/timing/time
index 35da97dfc887..35da97dfc887 100755
--- a/test/timing/time
+++ b/test/builtins/timing/time
diff --git a/test/timing/timing.h b/test/builtins/timing/timing.h
index bb6c41eb2a62..bb6c41eb2a62 100644
--- a/test/timing/timing.h
+++ b/test/builtins/timing/timing.h
diff --git a/test/timing/udivdi3.c b/test/builtins/timing/udivdi3.c
index 9c6a7e8cca9f..9c6a7e8cca9f 100644
--- a/test/timing/udivdi3.c
+++ b/test/builtins/timing/udivdi3.c
diff --git a/test/timing/umoddi3.c b/test/builtins/timing/umoddi3.c
index a81c46e52223..a81c46e52223 100644
--- a/test/timing/umoddi3.c
+++ b/test/builtins/timing/umoddi3.c
diff --git a/test/dfsan/CMakeLists.txt b/test/dfsan/CMakeLists.txt
new file mode 100644
index 000000000000..3fa1af24be51
--- /dev/null
+++ b/test/dfsan/CMakeLists.txt
@@ -0,0 +1,15 @@
+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_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS})
+if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND DFSAN_TEST_DEPS dfsan)
+endif()
+
+add_lit_testsuite(check-dfsan "Running the DataFlowSanitizer tests"
+ ${CMAKE_CURRENT_BINARY_DIR}
+ DEPENDS ${DFSAN_TEST_DEPS})
+set_target_properties(check-dfsan PROPERTIES FOLDER "DFSan tests")
diff --git a/test/dfsan/Inputs/flags_abilist.txt b/test/dfsan/Inputs/flags_abilist.txt
new file mode 100644
index 000000000000..94b1fa298259
--- /dev/null
+++ b/test/dfsan/Inputs/flags_abilist.txt
@@ -0,0 +1,10 @@
+fun:f=uninstrumented
+
+fun:main=uninstrumented
+fun:main=discard
+
+fun:dfsan_create_label=uninstrumented
+fun:dfsan_create_label=discard
+
+fun:dfsan_set_label=uninstrumented
+fun:dfsan_set_label=discard
diff --git a/test/dfsan/basic.c b/test/dfsan/basic.c
new file mode 100644
index 000000000000..6582727e5e61
--- /dev/null
+++ b/test/dfsan/basic.c
@@ -0,0 +1,28 @@
+// RUN: %clang_dfsan -m64 %s -o %t && %run %t
+// RUN: %clang_dfsan -mllvm -dfsan-args-abi -m64 %s -o %t && %run %t
+
+// Tests that labels are propagated through loads and stores.
+
+#include <sanitizer/dfsan_interface.h>
+#include <assert.h>
+
+int main(void) {
+ int i = 1;
+ dfsan_label i_label = dfsan_create_label("i", 0);
+ dfsan_set_label(i_label, &i, sizeof(i));
+
+ dfsan_label new_label = dfsan_get_label(i);
+ assert(i_label == new_label);
+
+ dfsan_label read_label = dfsan_read_label(&i, sizeof(i));
+ assert(i_label == read_label);
+
+ dfsan_label j_label = dfsan_create_label("j", 0);
+ dfsan_add_label(j_label, &i, sizeof(i));
+
+ read_label = dfsan_read_label(&i, sizeof(i));
+ assert(dfsan_has_label(read_label, i_label));
+ assert(dfsan_has_label(read_label, j_label));
+
+ return 0;
+}
diff --git a/test/dfsan/custom.cc b/test/dfsan/custom.cc
new file mode 100644
index 000000000000..d7bb3e3073fb
--- /dev/null
+++ b/test/dfsan/custom.cc
@@ -0,0 +1,958 @@
+// RUN: %clang_dfsan -m64 %s -o %t && DFSAN_OPTIONS="strict_data_dependencies=0" %run %t
+// RUN: %clang_dfsan -mllvm -dfsan-args-abi -m64 %s -o %t && DFSAN_OPTIONS="strict_data_dependencies=0" %run %t
+// RUN: %clang_dfsan -DSTRICT_DATA_DEPENDENCIES -m64 %s -o %t && %run %t
+// RUN: %clang_dfsan -DSTRICT_DATA_DEPENDENCIES -mllvm -dfsan-args-abi -m64 %s -o %t && %run %t
+
+// Tests custom implementations of various glibc functions.
+
+#include <sanitizer/dfsan_interface.h>
+
+#include <arpa/inet.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <link.h>
+#include <poll.h>
+#include <pthread.h>
+#include <pwd.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/select.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+dfsan_label i_label = 0;
+dfsan_label j_label = 0;
+dfsan_label k_label = 0;
+dfsan_label i_j_label = 0;
+
+#define ASSERT_ZERO_LABEL(data) \
+ assert(0 == dfsan_get_label((long) (data)))
+
+#define ASSERT_READ_ZERO_LABEL(ptr, size) \
+ assert(0 == dfsan_read_label(ptr, size))
+
+#define ASSERT_LABEL(data, label) \
+ assert(label == dfsan_get_label((long) (data)))
+
+#define ASSERT_READ_LABEL(ptr, size, label) \
+ assert(label == dfsan_read_label(ptr, size))
+
+void test_stat() {
+ int i = 1;
+ dfsan_set_label(i_label, &i, sizeof(i));
+
+ struct stat s;
+ s.st_dev = i;
+ assert(0 == stat("/", &s));
+ ASSERT_ZERO_LABEL(s.st_dev);
+
+ s.st_dev = i;
+ assert(-1 == stat("/nonexistent", &s));
+ ASSERT_LABEL(s.st_dev, i_label);
+}
+
+void test_fstat() {
+ int i = 1;
+ dfsan_set_label(i_label, &i, sizeof(i));
+
+ struct stat s;
+ int fd = open("/dev/zero", O_RDONLY);
+ s.st_dev = i;
+ int rv = fstat(fd, &s);
+ assert(0 == rv);
+ ASSERT_ZERO_LABEL(s.st_dev);
+}
+
+void test_memcmp() {
+ char str1[] = "str1", str2[] = "str2";
+ dfsan_set_label(i_label, &str1[3], 1);
+ dfsan_set_label(j_label, &str2[3], 1);
+
+ int rv = memcmp(str1, str2, sizeof(str1));
+ assert(rv < 0);
+#ifdef STRICT_DATA_DEPENDENCIES
+ ASSERT_ZERO_LABEL(rv);
+#else
+ ASSERT_LABEL(rv, i_j_label);
+#endif
+}
+
+void test_memcpy() {
+ char str1[] = "str1";
+ char str2[sizeof(str1)];
+ dfsan_set_label(i_label, &str1[3], 1);
+
+ ASSERT_ZERO_LABEL(memcpy(str2, str1, sizeof(str1)));
+ assert(0 == memcmp(str2, str1, sizeof(str1)));
+ ASSERT_ZERO_LABEL(str2[0]);
+ ASSERT_LABEL(str2[3], i_label);
+}
+
+void test_memset() {
+ char buf[8];
+ int j = 'a';
+ dfsan_set_label(j_label, &j, sizeof(j));
+
+ ASSERT_ZERO_LABEL(memset(&buf, j, sizeof(buf)));
+ for (int i = 0; i < 8; ++i) {
+ ASSERT_LABEL(buf[i], j_label);
+ assert(buf[i] == 'a');
+ }
+}
+
+void test_strcmp() {
+ char str1[] = "str1", str2[] = "str2";
+ dfsan_set_label(i_label, &str1[3], 1);
+ dfsan_set_label(j_label, &str2[3], 1);
+
+ int rv = strcmp(str1, str2);
+ assert(rv < 0);
+#ifdef STRICT_DATA_DEPENDENCIES
+ ASSERT_ZERO_LABEL(rv);
+#else
+ ASSERT_LABEL(rv, i_j_label);
+#endif
+}
+
+void test_strlen() {
+ char str1[] = "str1";
+ dfsan_set_label(i_label, &str1[3], 1);
+
+ int rv = strlen(str1);
+ assert(rv == 4);
+#ifdef STRICT_DATA_DEPENDENCIES
+ ASSERT_ZERO_LABEL(rv);
+#else
+ ASSERT_LABEL(rv, i_label);
+#endif
+}
+
+void test_strdup() {
+ char str1[] = "str1";
+ dfsan_set_label(i_label, &str1[3], 1);
+
+ char *strd = strdup(str1);
+ ASSERT_ZERO_LABEL(strd[0]);
+ ASSERT_LABEL(strd[3], i_label);
+ free(strd);
+}
+
+void test_strncpy() {
+ char str1[] = "str1";
+ char str2[sizeof(str1)];
+ dfsan_set_label(i_label, &str1[3], 1);
+
+ char *strd = strncpy(str2, str1, 5);
+ assert(strd == str2);
+ assert(strcmp(str1, str2) == 0);
+ ASSERT_ZERO_LABEL(strd);
+ ASSERT_ZERO_LABEL(strd[0]);
+ ASSERT_ZERO_LABEL(strd[1]);
+ ASSERT_ZERO_LABEL(strd[2]);
+ ASSERT_LABEL(strd[3], i_label);
+
+ strd = strncpy(str2, str1, 3);
+ assert(strd == str2);
+ assert(strncmp(str1, str2, 3) == 0);
+ ASSERT_ZERO_LABEL(strd);
+ ASSERT_ZERO_LABEL(strd[0]);
+ ASSERT_ZERO_LABEL(strd[1]);
+ ASSERT_ZERO_LABEL(strd[2]);
+}
+
+void test_strncmp() {
+ char str1[] = "str1", str2[] = "str2";
+ dfsan_set_label(i_label, &str1[3], 1);
+ dfsan_set_label(j_label, &str2[3], 1);
+
+ int rv = strncmp(str1, str2, sizeof(str1));
+ assert(rv < 0);
+#ifdef STRICT_DATA_DEPENDENCIES
+ ASSERT_ZERO_LABEL(rv);
+#else
+ ASSERT_LABEL(rv, dfsan_union(i_label, j_label));
+#endif
+
+ rv = strncmp(str1, str2, 3);
+ assert(rv == 0);
+ ASSERT_ZERO_LABEL(rv);
+}
+
+void test_strcasecmp() {
+ char str1[] = "str1", str2[] = "str2", str3[] = "Str1";
+ dfsan_set_label(i_label, &str1[3], 1);
+ dfsan_set_label(j_label, &str2[3], 1);
+ dfsan_set_label(j_label, &str3[2], 1);
+
+ int rv = strcasecmp(str1, str2);
+ assert(rv < 0);
+#ifdef STRICT_DATA_DEPENDENCIES
+ ASSERT_ZERO_LABEL(rv);
+#else
+ ASSERT_LABEL(rv, dfsan_union(i_label, j_label));
+#endif
+
+ rv = strcasecmp(str1, str3);
+ assert(rv == 0);
+#ifdef STRICT_DATA_DEPENDENCIES
+ ASSERT_ZERO_LABEL(rv);
+#else
+ ASSERT_LABEL(rv, dfsan_union(i_label, j_label));
+#endif
+}
+
+void test_strncasecmp() {
+ char str1[] = "Str1", str2[] = "str2";
+ dfsan_set_label(i_label, &str1[3], 1);
+ dfsan_set_label(j_label, &str2[3], 1);
+
+ int rv = strncasecmp(str1, str2, sizeof(str1));
+ assert(rv < 0);
+#ifdef STRICT_DATA_DEPENDENCIES
+ ASSERT_ZERO_LABEL(rv);
+#else
+ ASSERT_LABEL(rv, dfsan_union(i_label, j_label));
+#endif
+
+ rv = strncasecmp(str1, str2, 3);
+ assert(rv == 0);
+ ASSERT_ZERO_LABEL(rv);
+}
+
+void test_strchr() {
+ char str1[] = "str1";
+ dfsan_set_label(i_label, &str1[3], 1);
+
+ char *crv = strchr(str1, 'r');
+ assert(crv == &str1[2]);
+ ASSERT_ZERO_LABEL(crv);
+
+ crv = strchr(str1, '1');
+ assert(crv == &str1[3]);
+#ifdef STRICT_DATA_DEPENDENCIES
+ ASSERT_ZERO_LABEL(crv);
+#else
+ ASSERT_LABEL(crv, i_label);
+#endif
+
+ crv = strchr(str1, 'x');
+ assert(!crv);
+#ifdef STRICT_DATA_DEPENDENCIES
+ ASSERT_ZERO_LABEL(crv);
+#else
+ ASSERT_LABEL(crv, i_label);
+#endif
+}
+
+void test_calloc() {
+ // With any luck this sequence of calls will cause calloc to return the same
+ // pointer both times. This is probably the best we can do to test this
+ // function.
+ char *crv = (char *) calloc(4096, 1);
+ ASSERT_ZERO_LABEL(crv[0]);
+ dfsan_set_label(i_label, crv, 100);
+ free(crv);
+
+ crv = (char *) calloc(4096, 1);
+ ASSERT_ZERO_LABEL(crv[0]);
+ free(crv);
+}
+
+void test_read() {
+ char buf[16];
+ dfsan_set_label(i_label, buf, 1);
+ dfsan_set_label(j_label, buf + 15, 1);
+
+ ASSERT_LABEL(buf[0], i_label);
+ ASSERT_LABEL(buf[15], j_label);
+
+ int fd = open("/dev/zero", O_RDONLY);
+ int rv = read(fd, buf, sizeof(buf));
+ assert(rv == sizeof(buf));
+ ASSERT_ZERO_LABEL(rv);
+ ASSERT_ZERO_LABEL(buf[0]);
+ ASSERT_ZERO_LABEL(buf[15]);
+ close(fd);
+}
+
+void test_pread() {
+ char buf[16];
+ dfsan_set_label(i_label, buf, 1);
+ dfsan_set_label(j_label, buf + 15, 1);
+
+ ASSERT_LABEL(buf[0], i_label);
+ ASSERT_LABEL(buf[15], j_label);
+
+ int fd = open("/bin/sh", O_RDONLY);
+ int rv = pread(fd, buf, sizeof(buf), 0);
+ assert(rv == sizeof(buf));
+ ASSERT_ZERO_LABEL(rv);
+ ASSERT_ZERO_LABEL(buf[0]);
+ ASSERT_ZERO_LABEL(buf[15]);
+ close(fd);
+}
+
+void test_dlopen() {
+ void *map = dlopen(NULL, RTLD_NOW);
+ assert(map);
+ ASSERT_ZERO_LABEL(map);
+ dlclose(map);
+ map = dlopen("/nonexistent", RTLD_NOW);
+ assert(!map);
+ ASSERT_ZERO_LABEL(map);
+}
+
+void test_clock_gettime() {
+ struct timespec tp;
+ dfsan_set_label(j_label, ((char *)&tp) + 3, 1);
+ int t = clock_gettime(CLOCK_REALTIME, &tp);
+ assert(t == 0);
+ ASSERT_ZERO_LABEL(t);
+ ASSERT_ZERO_LABEL(((char *)&tp)[3]);
+}
+
+void test_ctime_r() {
+ char *buf = (char*) malloc(64);
+ time_t t = 0;
+
+ char *ret = ctime_r(&t, buf);
+ ASSERT_ZERO_LABEL(ret);
+ assert(buf == ret);
+ ASSERT_READ_ZERO_LABEL(buf, strlen(buf) + 1);
+
+ dfsan_set_label(i_label, &t, sizeof(t));
+ ret = ctime_r(&t, buf);
+ ASSERT_ZERO_LABEL(ret);
+ ASSERT_READ_LABEL(buf, strlen(buf) + 1, i_label);
+
+ t = 0;
+ dfsan_set_label(j_label, &buf, sizeof(&buf));
+ ret = ctime_r(&t, buf);
+ ASSERT_LABEL(ret, j_label);
+ ASSERT_READ_ZERO_LABEL(buf, strlen(buf) + 1);
+}
+
+static int write_callback_count = 0;
+static int last_fd;
+static const unsigned char *last_buf;
+static size_t last_count;
+
+void write_callback(int fd, const void *buf, size_t count) {
+ write_callback_count++;
+
+ last_fd = fd;
+ last_buf = (const unsigned char*) buf;
+ last_count = count;
+}
+
+void test_dfsan_set_write_callback() {
+ char buf[] = "Sample chars";
+ int buf_len = strlen(buf);
+
+ int fd = open("/dev/null", O_WRONLY);
+
+ dfsan_set_write_callback(write_callback);
+
+ write_callback_count = 0;
+
+ // Callback should be invoked on every call to write().
+ int res = write(fd, buf, buf_len);
+ assert(write_callback_count == 1);
+ ASSERT_READ_ZERO_LABEL(&res, sizeof(res));
+ ASSERT_READ_ZERO_LABEL(&last_fd, sizeof(last_fd));
+ ASSERT_READ_ZERO_LABEL(last_buf, sizeof(last_buf));
+ ASSERT_READ_ZERO_LABEL(&last_count, sizeof(last_count));
+
+ // Add a label to write() arguments. Check that the labels are readable from
+ // the values passed to the callback.
+ dfsan_set_label(i_label, &fd, sizeof(fd));
+ dfsan_set_label(j_label, &(buf[3]), 1);
+ dfsan_set_label(k_label, &buf_len, sizeof(buf_len));
+
+ res = write(fd, buf, buf_len);
+ assert(write_callback_count == 2);
+ ASSERT_READ_ZERO_LABEL(&res, sizeof(res));
+ ASSERT_READ_LABEL(&last_fd, sizeof(last_fd), i_label);
+ ASSERT_READ_LABEL(&last_buf[3], sizeof(last_buf[3]), j_label);
+ ASSERT_READ_LABEL(last_buf, sizeof(last_buf), j_label);
+ ASSERT_READ_LABEL(&last_count, sizeof(last_count), k_label);
+
+ dfsan_set_write_callback(NULL);
+}
+
+void test_fgets() {
+ char *buf = (char*) malloc(128);
+ FILE *f = fopen("/etc/passwd", "r");
+ dfsan_set_label(j_label, buf, 1);
+ char *ret = fgets(buf, sizeof(buf), f);
+ assert(ret == buf);
+ ASSERT_ZERO_LABEL(ret);
+ ASSERT_READ_ZERO_LABEL(buf, 128);
+ dfsan_set_label(j_label, &buf, sizeof(&buf));
+ ret = fgets(buf, sizeof(buf), f);
+ ASSERT_LABEL(ret, j_label);
+ fclose(f);
+}
+
+void test_getcwd() {
+ char buf[1024];
+ char *ptr = buf;
+ dfsan_set_label(i_label, buf + 2, 2);
+ char* ret = getcwd(buf, sizeof(buf));
+ assert(ret == buf);
+ assert(ret[0] == '/');
+ ASSERT_READ_ZERO_LABEL(buf + 2, 2);
+ dfsan_set_label(i_label, &ptr, sizeof(ptr));
+ ret = getcwd(ptr, sizeof(buf));
+ ASSERT_LABEL(ret, i_label);
+}
+
+void test_get_current_dir_name() {
+ char* ret = get_current_dir_name();
+ assert(ret);
+ assert(ret[0] == '/');
+ ASSERT_READ_ZERO_LABEL(ret, strlen(ret) + 1);
+}
+
+void test_gethostname() {
+ char buf[1024];
+ dfsan_set_label(i_label, buf + 2, 2);
+ assert(gethostname(buf, sizeof(buf)) == 0);
+ ASSERT_READ_ZERO_LABEL(buf + 2, 2);
+}
+
+void test_getrlimit() {
+ struct rlimit rlim;
+ dfsan_set_label(i_label, &rlim, sizeof(rlim));
+ assert(getrlimit(RLIMIT_CPU, &rlim) == 0);
+ ASSERT_READ_ZERO_LABEL(&rlim, sizeof(rlim));
+}
+
+void test_getrusage() {
+ struct rusage usage;
+ dfsan_set_label(i_label, &usage, sizeof(usage));
+ assert(getrusage(RUSAGE_SELF, &usage) == 0);
+ ASSERT_READ_ZERO_LABEL(&usage, sizeof(usage));
+}
+
+void test_strcpy() {
+ char src[] = "hello world";
+ char dst[sizeof(src) + 2];
+ dfsan_set_label(0, src, sizeof(src));
+ dfsan_set_label(0, dst, sizeof(dst));
+ dfsan_set_label(i_label, src + 2, 1);
+ dfsan_set_label(j_label, src + 3, 1);
+ dfsan_set_label(j_label, dst + 4, 1);
+ dfsan_set_label(i_label, dst + 12, 1);
+ char *ret = strcpy(dst, src);
+ assert(ret == dst);
+ assert(strcmp(src, dst) == 0);
+ for (int i = 0; i < strlen(src) + 1; ++i) {
+ assert(dfsan_get_label(dst[i]) == dfsan_get_label(src[i]));
+ }
+ // Note: if strlen(src) + 1 were used instead to compute the first untouched
+ // byte of dest, the label would be I|J. This is because strlen() might
+ // return a non-zero label, and because by default pointer labels are not
+ // ignored on loads.
+ ASSERT_LABEL(dst[12], i_label);
+}
+
+void test_strtol() {
+ char buf[] = "1234578910";
+ char *endptr = NULL;
+ dfsan_set_label(i_label, buf + 1, 1);
+ dfsan_set_label(j_label, buf + 10, 1);
+ long int ret = strtol(buf, &endptr, 10);
+ assert(ret == 1234578910);
+ assert(endptr == buf + 10);
+ ASSERT_LABEL(ret, i_j_label);
+}
+
+void test_strtoll() {
+ char buf[] = "1234578910 ";
+ char *endptr = NULL;
+ dfsan_set_label(i_label, buf + 1, 1);
+ dfsan_set_label(j_label, buf + 2, 1);
+ long long int ret = strtoll(buf, &endptr, 10);
+ assert(ret == 1234578910);
+ assert(endptr == buf + 10);
+ ASSERT_LABEL(ret, i_j_label);
+}
+
+void test_strtoul() {
+ char buf[] = "0xffffffffffffaa";
+ char *endptr = NULL;
+ dfsan_set_label(i_label, buf + 1, 1);
+ dfsan_set_label(j_label, buf + 2, 1);
+ long unsigned int ret = strtol(buf, &endptr, 16);
+ assert(ret == 72057594037927850);
+ assert(endptr == buf + 16);
+ ASSERT_LABEL(ret, i_j_label);
+}
+
+void test_strtoull() {
+ char buf[] = "0xffffffffffffffaa";
+ char *endptr = NULL;
+ dfsan_set_label(i_label, buf + 1, 1);
+ dfsan_set_label(j_label, buf + 2, 1);
+ long long unsigned int ret = strtoull(buf, &endptr, 16);
+ assert(ret == 0xffffffffffffffaa);
+ assert(endptr == buf + 18);
+ ASSERT_LABEL(ret, i_j_label);
+}
+
+void test_strtod() {
+ char buf[] = "12345.76 foo";
+ char *endptr = NULL;
+ dfsan_set_label(i_label, buf + 1, 1);
+ dfsan_set_label(j_label, buf + 6, 1);
+ double ret = strtod(buf, &endptr);
+ assert(ret == 12345.76);
+ assert(endptr == buf + 8);
+ ASSERT_LABEL(ret, i_j_label);
+}
+
+void test_time() {
+ time_t t = 0;
+ dfsan_set_label(i_label, &t, 1);
+ time_t ret = time(&t);
+ assert(ret == t);
+ assert(ret > 0);
+ ASSERT_ZERO_LABEL(t);
+}
+
+void test_inet_pton() {
+ char addr4[] = "127.0.0.1";
+ dfsan_set_label(i_label, addr4 + 3, 1);
+ struct in_addr in4;
+ int ret4 = inet_pton(AF_INET, addr4, &in4);
+ assert(ret4 == 1);
+ ASSERT_READ_LABEL(&in4, sizeof(in4), i_label);
+ assert(in4.s_addr == 0x0100007f);
+
+ char addr6[] = "::1";
+ dfsan_set_label(j_label, addr6 + 3, 1);
+ struct in6_addr in6;
+ int ret6 = inet_pton(AF_INET6, addr6, &in6);
+ assert(ret6 == 1);
+ ASSERT_READ_LABEL(((char *) &in6) + sizeof(in6) - 1, 1, j_label);
+}
+
+void test_localtime_r() {
+ time_t t0 = 1384800998;
+ struct tm t1;
+ dfsan_set_label(i_label, &t0, sizeof(t0));
+ struct tm* ret = localtime_r(&t0, &t1);
+ assert(ret == &t1);
+ assert(t1.tm_min == 56);
+ ASSERT_LABEL(t1.tm_mon, i_label);
+}
+
+void test_getpwuid_r() {
+ struct passwd pwd;
+ char buf[1024];
+ struct passwd *result;
+
+ dfsan_set_label(i_label, &pwd, 4);
+ int ret = getpwuid_r(0, &pwd, buf, sizeof(buf), &result);
+ assert(ret == 0);
+ assert(strcmp(pwd.pw_name, "root") == 0);
+ assert(result == &pwd);
+ ASSERT_READ_ZERO_LABEL(&pwd, 4);
+}
+
+void test_poll() {
+ struct pollfd fd;
+ fd.fd = 0;
+ fd.events = POLLIN;
+ dfsan_set_label(i_label, &fd.revents, sizeof(fd.revents));
+ int ret = poll(&fd, 1, 1);
+ ASSERT_ZERO_LABEL(fd.revents);
+ assert(ret >= 0);
+}
+
+void test_select() {
+ struct timeval t;
+ fd_set fds;
+ t.tv_sec = 2;
+ FD_SET(0, &fds);
+ dfsan_set_label(i_label, &fds, sizeof(fds));
+ dfsan_set_label(j_label, &t, sizeof(t));
+ int ret = select(1, &fds, NULL, NULL, &t);
+ assert(ret >= 0);
+ ASSERT_ZERO_LABEL(t.tv_sec);
+ ASSERT_READ_ZERO_LABEL(&fds, sizeof(fds));
+}
+
+void test_sched_getaffinity() {
+ cpu_set_t mask;
+ dfsan_set_label(j_label, &mask, 1);
+ int ret = sched_getaffinity(0, sizeof(mask), &mask);
+ assert(ret == 0);
+ ASSERT_READ_ZERO_LABEL(&mask, sizeof(mask));
+}
+
+void test_sigemptyset() {
+ sigset_t set;
+ dfsan_set_label(j_label, &set, 1);
+ int ret = sigemptyset(&set);
+ assert(ret == 0);
+ ASSERT_READ_ZERO_LABEL(&set, sizeof(set));
+}
+
+void test_sigaction() {
+ struct sigaction oldact;
+ dfsan_set_label(j_label, &oldact, 1);
+ int ret = sigaction(SIGUSR1, NULL, &oldact);
+ assert(ret == 0);
+ ASSERT_READ_ZERO_LABEL(&oldact, sizeof(oldact));
+}
+
+void test_gettimeofday() {
+ struct timeval tv;
+ struct timezone tz;
+ dfsan_set_label(i_label, &tv, sizeof(tv));
+ dfsan_set_label(j_label, &tz, sizeof(tz));
+ int ret = gettimeofday(&tv, &tz);
+ assert(ret == 0);
+ ASSERT_READ_ZERO_LABEL(&tv, sizeof(tv));
+ ASSERT_READ_ZERO_LABEL(&tz, sizeof(tz));
+}
+
+void *pthread_create_test_cb(void *p) {
+ assert(p == (void *)1);
+ ASSERT_ZERO_LABEL(p);
+ return (void *)2;
+}
+
+void test_pthread_create() {
+ pthread_t pt;
+ pthread_create(&pt, 0, pthread_create_test_cb, (void *)1);
+ void *cbrv;
+ pthread_join(pt, &cbrv);
+ assert(cbrv == (void *)2);
+}
+
+int dl_iterate_phdr_test_cb(struct dl_phdr_info *info, size_t size,
+ void *data) {
+ assert(data == (void *)3);
+ ASSERT_ZERO_LABEL(info);
+ ASSERT_ZERO_LABEL(size);
+ ASSERT_ZERO_LABEL(data);
+ return 0;
+}
+
+void test_dl_iterate_phdr() {
+ dl_iterate_phdr(dl_iterate_phdr_test_cb, (void *)3);
+}
+
+void test_strrchr() {
+ char str1[] = "str1str1";
+ dfsan_set_label(i_label, &str1[7], 1);
+
+ char *rv = strrchr(str1, 'r');
+ assert(rv == &str1[6]);
+#ifdef STRICT_DATA_DEPENDENCIES
+ ASSERT_ZERO_LABEL(rv);
+#else
+ ASSERT_LABEL(rv, i_label);
+#endif
+}
+
+void test_strstr() {
+ char str1[] = "str1str1";
+ dfsan_set_label(i_label, &str1[3], 1);
+ dfsan_set_label(j_label, &str1[5], 1);
+
+ char *rv = strstr(str1, "1s");
+ assert(rv == &str1[3]);
+#ifdef STRICT_DATA_DEPENDENCIES
+ ASSERT_ZERO_LABEL(rv);
+#else
+ ASSERT_LABEL(rv, i_label);
+#endif
+
+ rv = strstr(str1, "2s");
+ assert(rv == NULL);
+#ifdef STRICT_DATA_DEPENDENCIES
+ ASSERT_ZERO_LABEL(rv);
+#else
+ ASSERT_LABEL(rv, i_j_label);
+#endif
+}
+
+void test_memchr() {
+ char str1[] = "str1";
+ dfsan_set_label(i_label, &str1[3], 1);
+ dfsan_set_label(j_label, &str1[4], 1);
+
+ char *crv = (char *) memchr(str1, 'r', sizeof(str1));
+ assert(crv == &str1[2]);
+ ASSERT_ZERO_LABEL(crv);
+
+ crv = (char *) memchr(str1, '1', sizeof(str1));
+ assert(crv == &str1[3]);
+#ifdef STRICT_DATA_DEPENDENCIES
+ ASSERT_ZERO_LABEL(crv);
+#else
+ ASSERT_LABEL(crv, i_label);
+#endif
+
+ crv = (char *) memchr(str1, 'x', sizeof(str1));
+ assert(!crv);
+#ifdef STRICT_DATA_DEPENDENCIES
+ ASSERT_ZERO_LABEL(crv);
+#else
+ ASSERT_LABEL(crv, i_j_label);
+#endif
+}
+
+void alarm_handler(int unused) {
+ ;
+}
+
+void test_nanosleep() {
+ struct timespec req, rem;
+ req.tv_sec = 1;
+ req.tv_nsec = 0;
+ dfsan_set_label(i_label, &rem, sizeof(rem));
+
+ // non interrupted
+ int rv = nanosleep(&req, &rem);
+ assert(rv == 0);
+ ASSERT_ZERO_LABEL(rv);
+ ASSERT_READ_LABEL(&rem, 1, i_label);
+
+ // interrupted by an alarm
+ signal(SIGALRM, alarm_handler);
+ req.tv_sec = 3;
+ alarm(1);
+ rv = nanosleep(&req, &rem);
+ assert(rv == -1);
+ ASSERT_ZERO_LABEL(rv);
+ ASSERT_READ_ZERO_LABEL(&rem, sizeof(rem));
+}
+
+void test_socketpair() {
+ int fd[2];
+
+ dfsan_set_label(i_label, fd, sizeof(fd));
+ int rv = socketpair(PF_LOCAL, SOCK_STREAM, 0, fd);
+ assert(rv == 0);
+ ASSERT_ZERO_LABEL(rv);
+ ASSERT_READ_ZERO_LABEL(fd, sizeof(fd));
+}
+
+void test_write() {
+ int fd = open("/dev/null", O_WRONLY);
+
+ char buf[] = "a string";
+ int len = strlen(buf);
+
+ // The result of a write always unlabeled.
+ int res = write(fd, buf, len);
+ assert(res > 0);
+ ASSERT_ZERO_LABEL(res);
+
+ // Label all arguments to write().
+ dfsan_set_label(i_label, &(buf[3]), 1);
+ dfsan_set_label(j_label, &fd, sizeof(fd));
+ dfsan_set_label(i_label, &len, sizeof(len));
+
+ // The value returned by write() should have no label.
+ res = write(fd, buf, len);
+ ASSERT_ZERO_LABEL(res);
+
+ close(fd);
+}
+
+template <class T>
+void test_sprintf_chunk(const char* expected, const char* format, T arg) {
+ char buf[512];
+ memset(buf, 'a', sizeof(buf));
+
+ char padded_expected[512];
+ strcpy(padded_expected, "foo ");
+ strcat(padded_expected, expected);
+ strcat(padded_expected, " bar");
+
+ char padded_format[512];
+ strcpy(padded_format, "foo ");
+ strcat(padded_format, format);
+ strcat(padded_format, " bar");
+
+ // Non labelled arg.
+ assert(sprintf(buf, padded_format, arg) == strlen(padded_expected));
+ assert(strcmp(buf, padded_expected) == 0);
+ ASSERT_READ_LABEL(buf, strlen(padded_expected), 0);
+ memset(buf, 'a', sizeof(buf));
+
+ // Labelled arg.
+ dfsan_set_label(i_label, &arg, sizeof(arg));
+ assert(sprintf(buf, padded_format, arg) == strlen(padded_expected));
+ assert(strcmp(buf, padded_expected) == 0);
+ ASSERT_READ_LABEL(buf, 4, 0);
+ ASSERT_READ_LABEL(buf + 4, strlen(padded_expected) - 8, i_label);
+ ASSERT_READ_LABEL(buf + (strlen(padded_expected) - 4), 4, 0);
+}
+
+void test_sprintf() {
+ char buf[2048];
+ memset(buf, 'a', sizeof(buf));
+
+ // Test formatting (no conversion specifier).
+ assert(sprintf(buf, "Hello world!") == 12);
+ assert(strcmp(buf, "Hello world!") == 0);
+ ASSERT_READ_LABEL(buf, sizeof(buf), 0);
+
+ // Test for extra arguments.
+ assert(sprintf(buf, "Hello world!", 42, "hello") == 12);
+ assert(strcmp(buf, "Hello world!") == 0);
+ ASSERT_READ_LABEL(buf, sizeof(buf), 0);
+
+ // Test formatting & label propagation (multiple conversion specifiers): %s,
+ // %d, %n, %f, and %%.
+ const char* s = "world";
+ int m = 8;
+ int d = 27;
+ dfsan_set_label(k_label, (void *) (s + 1), 2);
+ dfsan_set_label(i_label, &m, sizeof(m));
+ dfsan_set_label(j_label, &d, sizeof(d));
+ int n;
+ int r = sprintf(buf, "hello %s, %-d/%d/%d %f %% %n%d", s, 2014, m, d,
+ 12345.6781234, &n, 1000);
+ assert(r == 42);
+ assert(strcmp(buf, "hello world, 2014/8/27 12345.678123 % 1000") == 0);
+ ASSERT_READ_LABEL(buf, 7, 0);
+ ASSERT_READ_LABEL(buf + 7, 2, k_label);
+ ASSERT_READ_LABEL(buf + 9, 9, 0);
+ ASSERT_READ_LABEL(buf + 18, 1, i_label);
+ ASSERT_READ_LABEL(buf + 19, 1, 0);
+ ASSERT_READ_LABEL(buf + 20, 2, j_label);
+ ASSERT_READ_LABEL(buf + 22, 15, 0);
+ ASSERT_LABEL(r, 0);
+ assert(n == 38);
+
+ // Test formatting & label propagation (single conversion specifier, with
+ // additional length and precision modifiers).
+ test_sprintf_chunk("-559038737", "%d", 0xdeadbeef);
+ test_sprintf_chunk("3735928559", "%u", 0xdeadbeef);
+ test_sprintf_chunk("12345", "%i", 12345);
+ test_sprintf_chunk("751", "%o", 0751);
+ test_sprintf_chunk("babe", "%x", 0xbabe);
+ test_sprintf_chunk("0000BABE", "%.8X", 0xbabe);
+ test_sprintf_chunk("-17", "%hhd", 0xdeadbeef);
+ test_sprintf_chunk("-16657", "%hd", 0xdeadbeef);
+ test_sprintf_chunk("deadbeefdeadbeef", "%lx", 0xdeadbeefdeadbeef);
+ test_sprintf_chunk("0xdeadbeefdeadbeef", "%p",
+ (void *) 0xdeadbeefdeadbeef);
+ test_sprintf_chunk("18446744073709551615", "%ju", (intmax_t) -1);
+ test_sprintf_chunk("18446744073709551615", "%zu", (size_t) -1);
+ test_sprintf_chunk("18446744073709551615", "%tu", (size_t) -1);
+
+ test_sprintf_chunk("0x1.f9acffa7eb6bfp-4", "%a", 0.123456);
+ test_sprintf_chunk("0X1.F9ACFFA7EB6BFP-4", "%A", 0.123456);
+ test_sprintf_chunk("0.12346", "%.5f", 0.123456);
+ test_sprintf_chunk("0.123456", "%g", 0.123456);
+ test_sprintf_chunk("1.234560e-01", "%e", 0.123456);
+ test_sprintf_chunk("1.234560E-01", "%E", 0.123456);
+ test_sprintf_chunk("0.1234567891234560", "%.16Lf",
+ (long double) 0.123456789123456);
+
+ test_sprintf_chunk("z", "%c", 'z');
+
+ // %n, %s, %d, %f, and %% already tested
+}
+
+void test_snprintf() {
+ char buf[2048];
+ memset(buf, 'a', sizeof(buf));
+ dfsan_set_label(0, buf, sizeof(buf));
+ const char* s = "world";
+ int y = 2014;
+ int m = 8;
+ int d = 27;
+ dfsan_set_label(k_label, (void *) (s + 1), 2);
+ dfsan_set_label(i_label, &y, sizeof(y));
+ dfsan_set_label(j_label, &m, sizeof(m));
+ int r = snprintf(buf, 19, "hello %s, %-d/%d/%d %f", s, y, m, d,
+ 12345.6781234);
+ // The return value is the number of bytes that would have been written to
+ // the final string if enough space had been available.
+ assert(r == 35);
+ assert(memcmp(buf, "hello world, 2014/", 19) == 0);
+ ASSERT_READ_LABEL(buf, 7, 0);
+ ASSERT_READ_LABEL(buf + 7, 2, k_label);
+ ASSERT_READ_LABEL(buf + 9, 4, 0);
+ ASSERT_READ_LABEL(buf + 13, 4, i_label);
+ ASSERT_READ_LABEL(buf + 17, 2, 0);
+ ASSERT_LABEL(r, 0);
+}
+
+int main(void) {
+ i_label = dfsan_create_label("i", 0);
+ j_label = dfsan_create_label("j", 0);
+ k_label = dfsan_create_label("k", 0);
+ i_j_label = dfsan_union(i_label, j_label);
+
+ test_calloc();
+ test_clock_gettime();
+ test_ctime_r();
+ test_dfsan_set_write_callback();
+ test_dl_iterate_phdr();
+ test_dlopen();
+ test_fgets();
+ test_fstat();
+ test_get_current_dir_name();
+ test_getcwd();
+ test_gethostname();
+ test_getpwuid_r();
+ test_getrlimit();
+ test_getrusage();
+ test_gettimeofday();
+ test_inet_pton();
+ test_localtime_r();
+ test_memchr();
+ test_memcmp();
+ test_memcpy();
+ test_memset();
+ test_nanosleep();
+ test_poll();
+ test_pread();
+ test_pthread_create();
+ test_read();
+ test_sched_getaffinity();
+ test_select();
+ test_sigaction();
+ test_sigemptyset();
+ test_snprintf();
+ test_socketpair();
+ test_sprintf();
+ test_stat();
+ test_strcasecmp();
+ test_strchr();
+ test_strcmp();
+ test_strcpy();
+ test_strdup();
+ test_strlen();
+ test_strncasecmp();
+ test_strncmp();
+ test_strncpy();
+ test_strrchr();
+ test_strstr();
+ test_strtod();
+ test_strtol();
+ test_strtoll();
+ test_strtoul();
+ test_strtoull();
+ test_time();
+ test_write();
+}
diff --git a/test/dfsan/dump_labels.c b/test/dfsan/dump_labels.c
new file mode 100644
index 000000000000..67801af1838f
--- /dev/null
+++ b/test/dfsan/dump_labels.c
@@ -0,0 +1,69 @@
+// RUN: %clang_dfsan -m64 %s -o %t
+// RUN: DFSAN_OPTIONS=dump_labels_at_exit=/dev/stdout %run %t 2>&1 | FileCheck %s
+// RUN: DFSAN_OPTIONS=dump_labels_at_exit=/dev/stdout not %run %t c 2>&1 | FileCheck %s --check-prefix=CHECK-OOL
+// RUN: DFSAN_OPTIONS=dump_labels_at_exit=/dev/stdout not %run %t u 2>&1 | FileCheck %s --check-prefix=CHECK-OOL
+
+// Tests that labels are properly dumped at program termination.
+
+#include <sanitizer/dfsan_interface.h>
+#include <assert.h>
+#include <stdio.h>
+
+int main(int argc, char** argv) {
+ int i = 1;
+ dfsan_label i_label = dfsan_create_label("i", 0);
+ dfsan_set_label(i_label, &i, sizeof(i));
+
+ int j = 2;
+ dfsan_label j_label = dfsan_create_label("j", 0);
+ dfsan_set_label(j_label, &j, sizeof(j));
+
+ int k = 3;
+ dfsan_label k_label = dfsan_create_label("k", 0);
+ dfsan_set_label(k_label, &k, sizeof(k));
+
+ dfsan_label ij_label = dfsan_get_label(i + j);
+ dfsan_label ijk_label = dfsan_get_label(i + j + k);
+
+ fprintf(stderr, "i %d j %d k %d ij %d ijk %d\n", i_label, j_label, k_label,
+ ij_label, ijk_label);
+
+ // CHECK: 1 0 0 i
+ // CHECK: 2 0 0 j
+ // CHECK: 3 0 0 k
+ // CHECK: 4 1 2
+ // CHECK: 5 3 4
+
+ if (argc > 1) {
+ // Exhaust the labels.
+ unsigned long num_labels = 1 << (sizeof(dfsan_label) * 8);
+ for (unsigned long i = ijk_label + 1; i < num_labels - 2; ++i) {
+ dfsan_label l = dfsan_create_label("l", 0);
+ assert(l == i);
+ }
+
+ // Consume the last available label.
+ dfsan_label l = dfsan_union(5, 6);
+ assert(l == num_labels - 2);
+
+ // Try to allocate another label (either explicitly or by unioning two
+ // existing labels), but expect a crash.
+ if (argv[1][0] == 'c') {
+ l = dfsan_create_label("l", 0);
+ } else {
+ l = dfsan_union(6, 7);
+ }
+
+ // CHECK-OOL: FATAL: DataFlowSanitizer: out of labels
+ // CHECK-OOL: 1 0 0 i
+ // CHECK-OOL: 2 0 0 j
+ // CHECK-OOL: 3 0 0 k
+ // CHECK-OOL: 4 1 2
+ // CHECK-OOL: 5 3 4
+ // CHECK-OOL: 6 0 0
+ // CHECK-OOL: 65534 5 6
+ // CHECK-OOL: 65535 0 0 <init label>
+ }
+
+ return 0;
+}
diff --git a/test/dfsan/flags.c b/test/dfsan/flags.c
new file mode 100644
index 000000000000..79069b96f83a
--- /dev/null
+++ b/test/dfsan/flags.c
@@ -0,0 +1,24 @@
+// RUN: %clang_dfsan -m64 %s -fsanitize-blacklist=%S/Inputs/flags_abilist.txt -mllvm -dfsan-debug-nonzero-labels -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clang_dfsan -m64 %s -fsanitize-blacklist=%S/Inputs/flags_abilist.txt -mllvm -dfsan-debug-nonzero-labels -o %t && DFSAN_OPTIONS=warn_unimplemented=0 %run %t 2>&1 | count 0
+// RUN: %clang_dfsan -m64 %s -fsanitize-blacklist=%S/Inputs/flags_abilist.txt -mllvm -dfsan-debug-nonzero-labels -o %t && DFSAN_OPTIONS=warn_nonzero_labels=1 %run %t 2>&1 | FileCheck --check-prefix=CHECK-NONZERO %s
+
+// Tests that flags work correctly.
+
+#include <sanitizer/dfsan_interface.h>
+
+int f(int i) {
+ return i;
+}
+
+int main(void) {
+ int i = 1;
+ dfsan_label i_label = dfsan_create_label("i", 0);
+ dfsan_set_label(i_label, &i, sizeof(i));
+
+ // CHECK: WARNING: DataFlowSanitizer: call to uninstrumented function f
+ // CHECK-NOT: WARNING: DataFlowSanitizer: saw nonzero label
+ // CHECK-NONZERO: WARNING: DataFlowSanitizer: saw nonzero label
+ f(i);
+
+ return 0;
+}
diff --git a/test/dfsan/fncall.c b/test/dfsan/fncall.c
new file mode 100644
index 000000000000..e780f3145e87
--- /dev/null
+++ b/test/dfsan/fncall.c
@@ -0,0 +1,26 @@
+// RUN: %clang_dfsan -m64 %s -o %t && %run %t
+// RUN: %clang_dfsan -mllvm -dfsan-args-abi -m64 %s -o %t && %run %t
+
+// Tests that labels are propagated through function calls.
+
+#include <sanitizer/dfsan_interface.h>
+#include <assert.h>
+
+int f(int x) {
+ int j = 2;
+ dfsan_label j_label = dfsan_create_label("j", 0);
+ dfsan_set_label(j_label, &j, sizeof(j));
+ return x + j;
+}
+
+int main(void) {
+ int i = 1;
+ dfsan_label i_label = dfsan_create_label("i", 0);
+ dfsan_set_label(i_label, &i, sizeof(i));
+
+ dfsan_label ij_label = dfsan_get_label(f(i));
+ assert(dfsan_has_label(ij_label, i_label));
+ assert(dfsan_has_label_with_desc(ij_label, "j"));
+
+ return 0;
+}
diff --git a/test/dfsan/label_count.c b/test/dfsan/label_count.c
new file mode 100644
index 000000000000..a4b608701811
--- /dev/null
+++ b/test/dfsan/label_count.c
@@ -0,0 +1,75 @@
+// RUN: %clang_dfsan -DLIB -m64 -c %s -o %t.lib.o && \
+// RUN: %clang_dfsan -m64 -c %s -o %t.o && \
+// RUN: %clang_dfsan -m64 %t.lib.o %t.o -o %t.bin && \
+// RUN: %run %t.bin
+
+// RUN: %clang_dfsan -mllvm -dfsan-args-abi -m64 -DLIB -c %s -o %t.lib.o && \
+// RUN: %clang_dfsan -mllvm -dfsan-args-abi -m64 -c %s -o %t.o && \
+// RUN: %clang_dfsan -mllvm -dfsan-args-abi -m64 %t.o %t.lib.o -o %t.bin && \
+// RUN: %run %t.bin
+
+#include <sanitizer/dfsan_interface.h>
+#include <assert.h>
+
+#ifdef LIB
+// Compiling this file with and without LIB defined allows this file to be
+// built as two separate translation units. This ensures that the code
+// can not be optimized in a way that removes behavior we wish to test. For
+// example, computing a value should cause labels to be allocated only if
+// the computation is actually done. Putting the computation here prevents
+// the compiler from optimizing away the computation (and labeling) that
+// tests wish to verify.
+
+int add_in_separate_translation_unit(int a, int b) {
+ return a + b;
+}
+
+int multiply_in_separate_translation_unit(int a, int b) {
+ return a * b;
+}
+
+#else
+
+int add_in_separate_translation_unit(int i, int j);
+int multiply_in_separate_translation_unit(int i, int j);
+
+int main(void) {
+ size_t label_count;
+
+ // No labels allocated yet.
+ label_count = dfsan_get_label_count();
+ assert(0 == label_count);
+
+ int i = 1;
+ dfsan_label i_label = dfsan_create_label("i", 0);
+ dfsan_set_label(i_label, &i, sizeof(i));
+
+ // One label allocated for i.
+ label_count = dfsan_get_label_count();
+ assert(1u == label_count);
+
+ int j = 2;
+ dfsan_label j_label = dfsan_create_label("j", 0);
+ dfsan_set_label(j_label, &j, sizeof(j));
+
+ // Check that a new label was allocated for j.
+ label_count = dfsan_get_label_count();
+ assert(2u == label_count);
+
+ // Create a value that combines i and j.
+ int i_plus_j = add_in_separate_translation_unit(i, j);
+
+ // Check that a label was created for the union of i and j.
+ label_count = dfsan_get_label_count();
+ assert(3u == label_count);
+
+ // Combine i and j in a different way. Check that the existing label is
+ // reused, and a new label is not created.
+ int j_times_i = multiply_in_separate_translation_unit(j, i);
+ label_count = dfsan_get_label_count();
+ assert(3u == label_count);
+ assert(dfsan_get_label(i_plus_j) == dfsan_get_label(j_times_i));
+
+ return 0;
+}
+#endif // #ifdef LIB
diff --git a/test/dfsan/lit.cfg b/test/dfsan/lit.cfg
new file mode 100644
index 000000000000..d4adb9a5110a
--- /dev/null
+++ b/test/dfsan/lit.cfg
@@ -0,0 +1,26 @@
+# -*- Python -*-
+
+import os
+
+# Setup config name.
+config.name = 'DataFlowSanitizer'
+
+# 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"]
+clang_dfsan_cxxflags = config.cxx_mode_flags + clang_dfsan_cflags
+
+def build_invocation(compile_flags):
+ return " " + " ".join([config.clang] + compile_flags) + " "
+
+config.substitutions.append( ("%clang_dfsan ", build_invocation(clang_dfsan_cflags)) )
+config.substitutions.append( ("%clangxx_dfsan ", build_invocation(clang_dfsan_cxxflags)) )
+
+# Default test suffixes.
+config.suffixes = ['.c', '.cc', '.cpp']
+
+# DataFlowSanitizer tests are currently supported on Linux only.
+if config.host_os not in ['Linux']:
+ config.unsupported = True
diff --git a/test/dfsan/lit.site.cfg.in b/test/dfsan/lit.site.cfg.in
new file mode 100644
index 000000000000..859284eca140
--- /dev/null
+++ b/test/dfsan/lit.site.cfg.in
@@ -0,0 +1,5 @@
+# Load common config for all compiler-rt lit tests.
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")
+
+# Load tool-specific config that would do the real work.
+lit_config.load_config(config, "@DFSAN_LIT_TESTS_DIR@/lit.cfg")
diff --git a/test/dfsan/propagate.c b/test/dfsan/propagate.c
new file mode 100644
index 000000000000..733538cb109a
--- /dev/null
+++ b/test/dfsan/propagate.c
@@ -0,0 +1,47 @@
+// RUN: %clang_dfsan -m64 %s -o %t && %run %t
+// RUN: %clang_dfsan -mllvm -dfsan-args-abi -m64 %s -o %t && %run %t
+
+// Tests that labels are propagated through computation and that union labels
+// are properly created.
+
+#include <sanitizer/dfsan_interface.h>
+#include <assert.h>
+
+int main(void) {
+ assert(dfsan_union(0, 0) == 0);
+
+ int i = 1;
+ dfsan_label i_label = dfsan_create_label("i", 0);
+ dfsan_set_label(i_label, &i, sizeof(i));
+
+ int j = 2;
+ dfsan_label j_label = dfsan_create_label("j", 0);
+ dfsan_set_label(j_label, &j, sizeof(j));
+
+ int k = 3;
+ dfsan_label k_label = dfsan_create_label("k", 0);
+ dfsan_set_label(k_label, &k, sizeof(k));
+
+ int k2 = 4;
+ dfsan_set_label(k_label, &k2, sizeof(k2));
+
+ dfsan_label ij_label = dfsan_get_label(i + j);
+ assert(dfsan_has_label(ij_label, i_label));
+ assert(dfsan_has_label(ij_label, j_label));
+ assert(!dfsan_has_label(ij_label, k_label));
+ // Test uniquing.
+ assert(dfsan_union(i_label, j_label) == ij_label);
+ assert(dfsan_union(j_label, i_label) == ij_label);
+
+ dfsan_label ijk_label = dfsan_get_label(i + j + k);
+ assert(dfsan_has_label(ijk_label, i_label));
+ assert(dfsan_has_label(ijk_label, j_label));
+ assert(dfsan_has_label(ijk_label, k_label));
+
+ assert(dfsan_get_label(k + k2) == k_label);
+
+ struct { int i, j; } s = { i, j };
+ assert(dfsan_read_label(&s, sizeof(s)) == ij_label);
+
+ return 0;
+}
diff --git a/test/dfsan/vararg.c b/test/dfsan/vararg.c
new file mode 100644
index 000000000000..2227ba715639
--- /dev/null
+++ b/test/dfsan/vararg.c
@@ -0,0 +1,24 @@
+// RUN: %clang_dfsan -m64 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: %run %t foo
+// RUN: %clang_dfsan -mllvm -dfsan-args-abi -m64 %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: %run %t foo
+
+#include <stdio.h>
+
+int do_nothing(const char *format, ...) {
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ int (*fp)(const char *, ...);
+
+ if (argc > 1)
+ fp = do_nothing;
+ else
+ fp = printf;
+
+ // CHECK: FATAL: DataFlowSanitizer: unsupported indirect call to vararg function printf
+ fp("hello %s\n", "world");
+}
diff --git a/test/dfsan/write_callback.c b/test/dfsan/write_callback.c
new file mode 100644
index 000000000000..bb35f3250740
--- /dev/null
+++ b/test/dfsan/write_callback.c
@@ -0,0 +1,110 @@
+// RUN: %clang_dfsan -m64 %s -o %t && %run %t | FileCheck %s
+// RUN: %clang_dfsan -mllvm -dfsan-args-abi -m64 %s -o %t && %run %t | FileCheck %s
+
+// Tests that the custom implementation of write() does writes with or without
+// a callback set using dfsan_set_write_callback().
+
+#include <sanitizer/dfsan_interface.h>
+
+#include <assert.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+// Check write callback arguments by having the callback store them in
+// the following variables:
+static int last_callback_arg_fd;
+static const void *last_callback_arg_buf;
+static size_t last_callback_arg_count;
+
+// Allow tests to check the number of callbacks made by incrementing
+// this count. When callbacks are verified, the count is reset.
+static int count_unverified_callbacks = 0;
+
+// This callbact will be installed using dfsan_set_write_callback()
+// in tests below.
+static void write_callback(int fd, const void *buf, size_t count) {
+ // Do not do anything in this function that might call write().
+ count_unverified_callbacks++;
+
+ last_callback_arg_fd = fd;
+ last_callback_arg_buf = buf;
+ last_callback_arg_count = count;
+}
+
+static void write_string_to_stdout(char *string) {
+ char *cur = string;
+ int bytes_left = strlen(string);
+ while (bytes_left > 0) {
+ int res = write(fileno(stdout), cur, bytes_left);
+ assert (res >= 0);
+ cur += res;
+ bytes_left -= res;
+ }
+}
+
+static void test_can_write_without_callback() {
+ dfsan_set_write_callback(NULL);
+ count_unverified_callbacks = 0;
+
+ char aString[] = "Test that writes work without callback.\n";
+ // CHECK: Test that writes work without callback.
+ write_string_to_stdout(aString);
+
+ assert(count_unverified_callbacks == 0);
+}
+
+static void test_can_write_with_callback() {
+ dfsan_set_write_callback(write_callback);
+
+ count_unverified_callbacks = 0;
+
+ char stringWithCallback[] = "Test that writes work with callback.\n";
+ // CHECK: Test that writes work with callback.
+ write_string_to_stdout(stringWithCallback);
+
+ // Data was written, so at least one call to write() was made.
+ // Because a write may not process all the bytes it is passed, there
+ // may have been several calls to write().
+ assert(count_unverified_callbacks > 0);
+ count_unverified_callbacks = 0;
+
+ dfsan_set_write_callback(NULL);
+
+ char stringWithoutCallback[] = "Writes work after the callback is removed.\n";
+ // CHECK: Writes work after the callback is removed.
+ write_string_to_stdout(stringWithoutCallback);
+ assert(count_unverified_callbacks == 0);
+}
+
+static void test_failing_write_runs_callback() {
+ // Open /dev/null in read-only mode. Calling write() on fd will fail.
+ int fd = open("/dev/null", O_RDONLY);
+ assert(fd != -1);
+
+ // Install a callback.
+ dfsan_set_write_callback(write_callback);
+
+ // Write to the read-only file handle. The write will fail, but the callback
+ // should still be invoked.
+ char aString[] = "This text will fail to be written.\n";
+ int len = strlen(aString);
+ int write_result = write(fd, aString, len);
+ assert(write_result == -1);
+
+ assert(count_unverified_callbacks == 1);
+ count_unverified_callbacks = 0;
+
+ assert(fd == last_callback_arg_fd);
+ assert(aString == last_callback_arg_buf);
+ assert(len == last_callback_arg_count);
+
+ close(fd);
+}
+
+int main(int argc, char* argv[]) {
+ test_can_write_without_callback();
+ test_can_write_with_callback();
+ test_failing_write_runs_callback();
+}
diff --git a/test/lit.common.cfg b/test/lit.common.cfg
new file mode 100644
index 000000000000..0ee2b84481da
--- /dev/null
+++ b/test/lit.common.cfg
@@ -0,0 +1,89 @@
+# -*- Python -*-
+
+# Configuration file for 'lit' test runner.
+# This file contains common rules for various compiler-rt testsuites.
+# It is mostly copied from lit.cfg used by Clang.
+import os
+import platform
+
+import lit.formats
+import lit.util
+
+# Setup test format
+execute_external = (platform.system() != 'Windows'
+ or lit_config.getBashPath() not in [None, ""])
+config.test_format = lit.formats.ShTest(execute_external)
+
+# Setup clang binary.
+compiler_path = getattr(config, 'clang', None)
+if (not compiler_path) or (not os.path.exists(compiler_path)):
+ lit_config.fatal("Can't find compiler on path %r" % compiler_path)
+
+compiler_id = getattr(config, 'compiler_id', None)
+if compiler_id == "Clang":
+ if platform.system() != 'Windows':
+ config.cxx_mode_flags = ["--driver-mode=g++"]
+ else:
+ config.cxx_mode_flags = []
+ # We assume that sanitizers should provide good enough error
+ # reports and stack traces even with minimal debug info.
+ config.debug_info_flags = ["-gline-tables-only"]
+elif compiler_id == 'GNU':
+ config.cxx_mode_flags = ["-x c++"]
+ config.debug_info_flags = ["-g"]
+else:
+ lit_config.fatal("Unsupported compiler id: %r" % compiler_id)
+# Add compiler ID to the list of available features.
+config.available_features.add(compiler_id)
+
+# Clear some environment variables that might affect Clang.
+possibly_dangerous_env_vars = ['COMPILER_PATH', 'RC_DEBUG_OPTIONS',
+ 'CINDEXTEST_PREAMBLE_FILE', 'LIBRARY_PATH',
+ 'CPATH', 'C_INCLUDE_PATH', 'CPLUS_INCLUDE_PATH',
+ 'OBJC_INCLUDE_PATH', 'OBJCPLUS_INCLUDE_PATH',
+ 'LIBCLANG_TIMING', 'LIBCLANG_OBJTRACKING',
+ 'LIBCLANG_LOGGING', 'LIBCLANG_BGPRIO_INDEX',
+ 'LIBCLANG_BGPRIO_EDIT', 'LIBCLANG_NOTHREADS',
+ 'LIBCLANG_RESOURCE_USAGE',
+ 'LIBCLANG_CODE_COMPLETION_LOGGING']
+# Clang/Win32 may refer to %INCLUDE%. vsvarsall.bat sets it.
+if platform.system() != 'Windows':
+ possibly_dangerous_env_vars.append('INCLUDE')
+for name in possibly_dangerous_env_vars:
+ if name in config.environment:
+ del config.environment[name]
+
+# Tweak PATH to include llvm tools dir.
+llvm_tools_dir = getattr(config, 'llvm_tools_dir', None)
+if (not llvm_tools_dir) or (not os.path.exists(llvm_tools_dir)):
+ lit_config.fatal("Invalid llvm_tools_dir config attribute: %r" % llvm_tools_dir)
+path = os.path.pathsep.join((llvm_tools_dir, config.environment['PATH']))
+config.environment['PATH'] = path
+
+# Help MSVS link.exe find the standard libraries.
+if platform.system() == 'Windows':
+ config.environment['LIB'] = os.environ['LIB']
+
+# Use ugly construction to explicitly prohibit "clang", "clang++" etc.
+# in RUN lines.
+config.substitutions.append(
+ (' clang', """\n\n*** Do not use 'clangXXX' in tests,
+ instead define '%clangXXX' substitution in lit config. ***\n\n""") )
+
+# Allow tests to be executed on a simulator or remotely.
+config.substitutions.append( ('%run', config.emulator) )
+
+# Define CHECK-%os to check for OS-dependent output.
+config.substitutions.append( ('CHECK-%os', ("CHECK-" + config.host_os)))
+
+# Add supported compiler_rt architectures to a list of available features.
+compiler_rt_arch = getattr(config, 'compiler_rt_arch', None)
+if compiler_rt_arch:
+ for arch in compiler_rt_arch.split(";"):
+ config.available_features.add(arch + "-supported-target")
+
+compiler_rt_debug = getattr(config, 'compiler_rt_debug', False)
+if not compiler_rt_debug:
+ config.available_features.add('compiler-rt-optimized')
+
+lit.util.usePlatformSdkOnDarwin(config, lit_config)
diff --git a/test/lit.common.configured.in b/test/lit.common.configured.in
new file mode 100644
index 000000000000..beecaa25886a
--- /dev/null
+++ b/test/lit.common.configured.in
@@ -0,0 +1,38 @@
+## Autogenerated by LLVM/Clang configuration.
+# Do not edit!
+
+# Set attribute value if it is unset.
+def set_default(attr, value):
+ if not getattr(config, attr, None):
+ setattr(config, attr, value)
+
+# Generic config options for all compiler-rt lit tests.
+set_default("target_triple", "@COMPILER_RT_TEST_TARGET_TRIPLE@")
+set_default("target_cflags", "@COMPILER_RT_TEST_COMPILER_CFLAGS@")
+set_default("host_arch", "@HOST_ARCH@")
+set_default("target_arch", "@COMPILER_RT_TEST_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_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("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@")
+
+# LLVM tools dir can be passed in lit parameters, so try to
+# apply substitution.
+try:
+ config.llvm_tools_dir = config.llvm_tools_dir % lit_config.params
+except KeyError,e:
+ key, = e.args
+ lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key))
+
+# Setup attributes common for all compiler-rt projects.
+lit_config.load_config(config, "@COMPILER_RT_SOURCE_DIR@/test/lit.common.cfg")
diff --git a/test/lsan/CMakeLists.txt b/test/lsan/CMakeLists.txt
new file mode 100644
index 000000000000..7f49b0d3983d
--- /dev/null
+++ b/test/lsan/CMakeLists.txt
@@ -0,0 +1,23 @@
+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_LIT_TEST_MODE "AddressSanitizer")
+configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/AsanConfig/lit.site.cfg)
+
+if(NOT APPLE AND NOT ANDROID)
+ 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
+ DEPENDS ${LSAN_TEST_DEPS})
+ set_target_properties(check-lsan PROPERTIES FOLDER "LSan tests")
+endif()
diff --git a/test/lsan/TestCases/cleanup_in_tsd_destructor.cc b/test/lsan/TestCases/cleanup_in_tsd_destructor.cc
new file mode 100644
index 000000000000..5335454ffbeb
--- /dev/null
+++ b/test/lsan/TestCases/cleanup_in_tsd_destructor.cc
@@ -0,0 +1,45 @@
+// Regression test for thread lifetime tracking. Thread data should be
+// considered live during the thread's termination, at least until the
+// user-installed TSD destructors have finished running (since they may contain
+// additional cleanup tasks). LSan doesn't actually meet that goal 100%, but it
+// makes its best effort.
+// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE:use_tls=1 %run %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE:use_tls=0 not %run %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sanitizer/lsan_interface.h"
+
+pthread_key_t key;
+__thread void *p;
+
+void key_destructor(void *arg) {
+ // Generally this may happen on a different thread.
+ __lsan_do_leak_check();
+}
+
+void *thread_func(void *arg) {
+ p = malloc(1337);
+ fprintf(stderr, "Test alloc: %p.\n", p);
+ int res = pthread_setspecific(key, (void*)1);
+ assert(res == 0);
+ return 0;
+}
+
+int main() {
+ int res = pthread_key_create(&key, &key_destructor);
+ assert(res == 0);
+ pthread_t thread_id;
+ res = pthread_create(&thread_id, 0, thread_func, 0);
+ assert(res == 0);
+ res = pthread_join(thread_id, 0);
+ assert(res == 0);
+ return 0;
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: [[ADDR]] (1337 bytes)
diff --git a/test/lsan/TestCases/disabler.cc b/test/lsan/TestCases/disabler.cc
new file mode 100644
index 000000000000..f83106501fa3
--- /dev/null
+++ b/test/lsan/TestCases/disabler.cc
@@ -0,0 +1,23 @@
+// Test for ScopedDisabler.
+// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0:use_tls=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sanitizer/lsan_interface.h"
+
+int main() {
+ void **p;
+ {
+ __lsan::ScopedDisabler d;
+ p = new void *;
+ }
+ *reinterpret_cast<void **>(p) = malloc(666);
+ void *q = malloc(1337);
+ // Break optimization.
+ fprintf(stderr, "Test alloc: %p.\n", q);
+ return 0;
+}
+// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: 1337 byte(s) leaked in 1 allocation(s)
diff --git a/test/lsan/TestCases/disabler_in_tsd_destructor.cc b/test/lsan/TestCases/disabler_in_tsd_destructor.cc
new file mode 100644
index 000000000000..a0012c74dd96
--- /dev/null
+++ b/test/lsan/TestCases/disabler_in_tsd_destructor.cc
@@ -0,0 +1,38 @@
+// Regression test. Disabler should not depend on TSD validity.
+// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0:use_tls=1"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sanitizer/lsan_interface.h"
+
+pthread_key_t key;
+
+void key_destructor(void *arg) {
+ __lsan::ScopedDisabler d;
+ void *p = malloc(1337);
+ // Break optimization.
+ fprintf(stderr, "Test alloc: %p.\n", p);
+ pthread_setspecific(key, 0);
+}
+
+void *thread_func(void *arg) {
+ int res = pthread_setspecific(key, (void*)1);
+ assert(res == 0);
+ return 0;
+}
+
+int main() {
+ int res = pthread_key_create(&key, &key_destructor);
+ assert(res == 0);
+ pthread_t thread_id;
+ res = pthread_create(&thread_id, 0, thread_func, 0);
+ assert(res == 0);
+ res = pthread_join(thread_id, 0);
+ assert(res == 0);
+ return 0;
+}
diff --git a/test/lsan/TestCases/do_leak_check_override.cc b/test/lsan/TestCases/do_leak_check_override.cc
new file mode 100644
index 000000000000..bedb0cad6908
--- /dev/null
+++ b/test/lsan/TestCases/do_leak_check_override.cc
@@ -0,0 +1,36 @@
+// Test for __lsan_do_leak_check(). We test it by making the leak check run
+// before global destructors, which also tests compatibility with HeapChecker's
+// "normal" mode (LSan runs in "strict" mode by default).
+// RUN: LSAN_BASE="use_stacks=0:use_registers=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t 2>&1 | FileCheck --check-prefix=CHECK-strict %s
+// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t foo 2>&1 | FileCheck --check-prefix=CHECK-normal %s
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sanitizer/lsan_interface.h>
+
+struct LeakyGlobal {
+ LeakyGlobal() {
+ p = malloc(1337);
+ }
+ ~LeakyGlobal() {
+ p = 0;
+ }
+ void *p;
+};
+
+LeakyGlobal leaky_global;
+
+int main(int argc, char *argv[]) {
+ // Register leak check to run before global destructors.
+ if (argc > 1)
+ atexit(&__lsan_do_leak_check);
+ void *p = malloc(666);
+ printf("Test alloc: %p\n", p);
+ printf("Test alloc in leaky global: %p\n", leaky_global.p);
+ return 0;
+}
+
+// CHECK-strict: SUMMARY: {{(Leak|Address)}}Sanitizer: 2003 byte(s) leaked in 2 allocation(s)
+// CHECK-normal: SUMMARY: {{(Leak|Address)}}Sanitizer: 666 byte(s) leaked in 1 allocation(s)
diff --git a/test/lsan/TestCases/fork.cc b/test/lsan/TestCases/fork.cc
new file mode 100644
index 000000000000..9e72fe871cf1
--- /dev/null
+++ b/test/lsan/TestCases/fork.cc
@@ -0,0 +1,24 @@
+// Test that thread local data is handled correctly after forking without exec().
+// RUN: %clangxx_lsan %s -o %t
+// RUN: %run %t 2>&1
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+__thread void *thread_local_var;
+
+int main() {
+ int status = 0;
+ thread_local_var = malloc(1337);
+ pid_t pid = fork();
+ assert(pid >= 0);
+ if (pid > 0) {
+ waitpid(pid, &status, 0);
+ assert(WIFEXITED(status));
+ return WEXITSTATUS(status);
+ }
+ return 0;
+}
diff --git a/test/lsan/TestCases/fork_threaded.cc b/test/lsan/TestCases/fork_threaded.cc
new file mode 100644
index 000000000000..62702b4dfe47
--- /dev/null
+++ b/test/lsan/TestCases/fork_threaded.cc
@@ -0,0 +1,43 @@
+// Test that thread local data is handled correctly after forking without
+// exec(). In this test leak checking is initiated from a non-main thread.
+// RUN: %clangxx_lsan %s -o %t
+// RUN: %run %t 2>&1
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+__thread void *thread_local_var;
+
+void *exit_thread_func(void *arg) {
+ exit(0);
+}
+
+void ExitFromThread() {
+ pthread_t tid;
+ int res;
+ res = pthread_create(&tid, 0, exit_thread_func, 0);
+ assert(res == 0);
+ pthread_join(tid, 0);
+}
+
+int main() {
+ int status = 0;
+ thread_local_var = malloc(1337);
+ pid_t pid = fork();
+ assert(pid >= 0);
+ if (pid > 0) {
+ waitpid(pid, &status, 0);
+ assert(WIFEXITED(status));
+ return WEXITSTATUS(status);
+ } else {
+ // Spawn a thread and call exit() from there, to check that we track main
+ // thread's pid correctly even if leak checking is initiated from another
+ // thread.
+ ExitFromThread();
+ }
+ return 0;
+}
diff --git a/test/lsan/TestCases/high_allocator_contention.cc b/test/lsan/TestCases/high_allocator_contention.cc
new file mode 100644
index 000000000000..2543897bcbb4
--- /dev/null
+++ b/test/lsan/TestCases/high_allocator_contention.cc
@@ -0,0 +1,48 @@
+// A benchmark that executes malloc/free pairs in parallel.
+// Usage: ./a.out number_of_threads total_number_of_allocations
+// RUN: %clangxx_lsan %s -o %t
+// RUN: %run %t 5 1000000 2>&1
+#include <assert.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int num_threads;
+int total_num_alloc;
+const int kMaxNumThreads = 5000;
+pthread_t tid[kMaxNumThreads];
+
+pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+bool go = false;
+
+void *thread_fun(void *arg) {
+ pthread_mutex_lock(&mutex);
+ while (!go) pthread_cond_wait(&cond, &mutex);
+ pthread_mutex_unlock(&mutex);
+ for (int i = 0; i < total_num_alloc / num_threads; i++) {
+ void *p = malloc(10);
+ __asm__ __volatile__("" : : "r"(p) : "memory");
+ free((void *)p);
+ }
+ return 0;
+}
+
+int main(int argc, char** argv) {
+ assert(argc == 3);
+ num_threads = atoi(argv[1]);
+ assert(num_threads > 0);
+ assert(num_threads <= kMaxNumThreads);
+ total_num_alloc = atoi(argv[2]);
+ assert(total_num_alloc > 0);
+ printf("%d threads, %d allocations in each\n", num_threads,
+ total_num_alloc / num_threads);
+ for (int i = 0; i < num_threads; i++)
+ pthread_create(&tid[i], 0, thread_fun, 0);
+ pthread_mutex_lock(&mutex);
+ go = true;
+ pthread_cond_broadcast(&cond);
+ pthread_mutex_unlock(&mutex);
+ for (int i = 0; i < num_threads; i++) pthread_join(tid[i], 0);
+ return 0;
+}
diff --git a/test/lsan/TestCases/ignore_object.cc b/test/lsan/TestCases/ignore_object.cc
new file mode 100644
index 000000000000..38d76e6798b2
--- /dev/null
+++ b/test/lsan/TestCases/ignore_object.cc
@@ -0,0 +1,24 @@
+// Test for __lsan_ignore_object().
+// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0:use_tls=0:verbosity=2"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sanitizer/lsan_interface.h"
+
+int main() {
+ // Explicitly ignored object.
+ void **p = new void *;
+ // Transitively ignored object.
+ *p = malloc(666);
+ // Non-ignored object.
+ volatile void *q = malloc(1337);
+ fprintf(stderr, "Test alloc: %p.\n", p);
+ __lsan_ignore_object(p);
+ return 0;
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: ignoring heap object at [[ADDR]]
+// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: 1337 byte(s) leaked in 1 allocation(s)
diff --git a/test/lsan/TestCases/ignore_object_errors.cc b/test/lsan/TestCases/ignore_object_errors.cc
new file mode 100644
index 000000000000..39b9b0288bb3
--- /dev/null
+++ b/test/lsan/TestCases/ignore_object_errors.cc
@@ -0,0 +1,22 @@
+// Test for incorrect use of __lsan_ignore_object().
+// RUN: LSAN_BASE="verbosity=2"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sanitizer/lsan_interface.h"
+
+int main() {
+ void *p = malloc(1337);
+ fprintf(stderr, "Test alloc: %p.\n", p);
+ __lsan_ignore_object(p);
+ __lsan_ignore_object(p);
+ free(p);
+ __lsan_ignore_object(p);
+ return 0;
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: heap object at [[ADDR]] is already being ignored
+// CHECK: no heap object found at [[ADDR]]
diff --git a/test/lsan/TestCases/large_allocation_leak.cc b/test/lsan/TestCases/large_allocation_leak.cc
new file mode 100644
index 000000000000..f41143a8a501
--- /dev/null
+++ b/test/lsan/TestCases/large_allocation_leak.cc
@@ -0,0 +1,18 @@
+// Test that LargeMmapAllocator's chunks aren't reachable via some internal data structure.
+// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+ // maxsize in primary allocator is always less than this (1 << 25).
+ void *large_alloc = malloc(33554432);
+ fprintf(stderr, "Test alloc: %p.\n", large_alloc);
+ return 0;
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: LeakSanitizer: detected memory leaks
+// CHECK: [[ADDR]] (33554432 bytes)
+// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
diff --git a/test/lsan/TestCases/leak_check_at_exit.cc b/test/lsan/TestCases/leak_check_at_exit.cc
new file mode 100644
index 000000000000..fe3f70e40005
--- /dev/null
+++ b/test/lsan/TestCases/leak_check_at_exit.cc
@@ -0,0 +1,21 @@
+// Test for the leak_check_at_exit flag.
+// RUN: LSAN_BASE="use_stacks=0:use_registers=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-do
+// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-do
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"leak_check_at_exit=0" not %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-do
+// RUN: LSAN_OPTIONS=%LSAN_BASE:"leak_check_at_exit=0" %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-dont
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sanitizer/lsan_interface.h>
+
+int main(int argc, char *argv[]) {
+ fprintf(stderr, "Test alloc: %p.\n", malloc(1337));
+ if (argc > 1)
+ __lsan_do_leak_check();
+ return 0;
+}
+
+// CHECK-do: SUMMARY: {{(Leak|Address)}}Sanitizer:
+// CHECK-dont-NOT: SUMMARY: {{(Leak|Address)}}Sanitizer:
diff --git a/test/lsan/TestCases/leak_check_before_thread_started.cc b/test/lsan/TestCases/leak_check_before_thread_started.cc
new file mode 100644
index 000000000000..891cd699a255
--- /dev/null
+++ b/test/lsan/TestCases/leak_check_before_thread_started.cc
@@ -0,0 +1,32 @@
+// Regression test for http://llvm.org/bugs/show_bug.cgi?id=21621
+// This test relies on timing between threads, so any failures will be flaky.
+// RUN: LSAN_BASE="use_stacks=0:use_registers=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: %run %t
+#include <assert.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+void *func(void *arg) {
+ sleep(1);
+ free(arg);
+ return 0;
+}
+
+void create_detached_thread() {
+ pthread_t thread_id;
+ pthread_attr_t attr;
+
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+ void *arg = malloc(1337);
+ assert(arg);
+ int res = pthread_create(&thread_id, &attr, func, arg);
+ assert(res == 0);
+}
+
+int main() {
+ create_detached_thread();
+}
diff --git a/test/lsan/TestCases/link_turned_off.cc b/test/lsan/TestCases/link_turned_off.cc
new file mode 100644
index 000000000000..2482f6197d92
--- /dev/null
+++ b/test/lsan/TestCases/link_turned_off.cc
@@ -0,0 +1,24 @@
+// Test for disabling LSan at link-time.
+// RUN: LSAN_BASE="use_stacks=0:use_registers=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t foo 2>&1 | FileCheck %s
+
+#include <sanitizer/lsan_interface.h>
+
+int argc_copy;
+
+extern "C" {
+int __lsan_is_turned_off() {
+ return (argc_copy == 1);
+}
+}
+
+int main(int argc, char *argv[]) {
+ volatile int *x = new int;
+ *x = 42;
+ argc_copy = argc;
+ return 0;
+}
+
+// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: 4 byte(s) leaked in 1 allocation(s)
diff --git a/test/lsan/TestCases/new_array_with_dtor_0.cc b/test/lsan/TestCases/new_array_with_dtor_0.cc
new file mode 100644
index 000000000000..59259616e827
--- /dev/null
+++ b/test/lsan/TestCases/new_array_with_dtor_0.cc
@@ -0,0 +1,19 @@
+// Regression test:
+// https://code.google.com/p/address-sanitizer/issues/detail?id=257
+// RUN: %clangxx_lsan %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+
+struct T {
+ ~T() { printf("~T\n"); }
+};
+
+T *t;
+
+int main(int argc, char **argv) {
+ t = new T[argc - 1];
+ printf("OK\n");
+}
+
+// CHECK: OK
+
diff --git a/test/lsan/TestCases/pointer_to_self.cc b/test/lsan/TestCases/pointer_to_self.cc
new file mode 100644
index 000000000000..63bde2ccf35d
--- /dev/null
+++ b/test/lsan/TestCases/pointer_to_self.cc
@@ -0,0 +1,18 @@
+// Regression test: pointers to self should not confuse LSan into thinking the
+// object is indirectly leaked. Only external pointers count.
+// RUN: LSAN_BASE="report_objects=1:use_registers=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_stacks=0" not %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+ void *p = malloc(1337);
+ *reinterpret_cast<void **>(p) = p;
+ fprintf(stderr, "Test alloc: %p.\n", p);
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: LeakSanitizer: detected memory leaks
+// CHECK: [[ADDR]] (1337 bytes)
+// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
diff --git a/test/lsan/TestCases/print_suppressions.cc b/test/lsan/TestCases/print_suppressions.cc
new file mode 100644
index 000000000000..b292c0a7c3cf
--- /dev/null
+++ b/test/lsan/TestCases/print_suppressions.cc
@@ -0,0 +1,33 @@
+// Print matched suppressions only if print_suppressions=1 AND at least one is
+// matched. Default is print_suppressions=true.
+// RUN: LSAN_BASE="use_registers=0:use_stacks=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE:print_suppressions=0 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-dont-print
+// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-dont-print
+// RUN: LSAN_OPTIONS=$LSAN_BASE:print_suppressions=0 %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-dont-print
+// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-print
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sanitizer/lsan_interface.h"
+
+extern "C"
+const char *__lsan_default_suppressions() {
+ return "leak:*LSanTestLeakingFunc*";
+}
+
+void LSanTestLeakingFunc() {
+ void *p = malloc(666);
+ fprintf(stderr, "Test alloc: %p.\n", p);
+}
+
+int main(int argc, char **argv) {
+ printf("print for nonempty output\n");
+ if (argc > 1)
+ LSanTestLeakingFunc();
+ return 0;
+}
+// CHECK-print: Suppressions used:
+// CHECK-print: 1 666 *LSanTestLeakingFunc*
+// CHECK-dont-print-NOT: Suppressions used:
diff --git a/test/lsan/TestCases/register_root_region.cc b/test/lsan/TestCases/register_root_region.cc
new file mode 100644
index 000000000000..6fc84c2fb50f
--- /dev/null
+++ b/test/lsan/TestCases/register_root_region.cc
@@ -0,0 +1,32 @@
+// Test for __lsan_(un)register_root_region().
+// RUN: LSAN_BASE="use_stacks=0:use_registers=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t foo 2>&1 | FileCheck %s
+// RUN: LSAN_OPTIONS=$LSAN_BASE:use_root_regions=0 not %run %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <sanitizer/lsan_interface.h>
+
+int main(int argc, char *argv[]) {
+ size_t size = getpagesize() * 2;
+ void *p =
+ mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+ assert(p);
+ // Make half of the memory inaccessible. LSan must not crash trying to read it.
+ assert(0 == mprotect((char *)p + size / 2, size / 2, PROT_NONE));
+
+ __lsan_register_root_region(p, size);
+ *((void **)p) = malloc(1337);
+ fprintf(stderr, "Test alloc: %p.\n", p);
+ if (argc > 1)
+ __lsan_unregister_root_region(p, size);
+ return 0;
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: 1337 byte(s) leaked in 1 allocation(s)
diff --git a/test/lsan/TestCases/sanity_check_pure_c.c b/test/lsan/TestCases/sanity_check_pure_c.c
new file mode 100644
index 000000000000..085412b47d55
--- /dev/null
+++ b/test/lsan/TestCases/sanity_check_pure_c.c
@@ -0,0 +1,10 @@
+// Check that we can build C code.
+// RUN: %clang_lsan %s -o %t
+#ifdef __cplusplus
+#error "This test must be built in C mode"
+#endif
+
+int main() {
+ // FIXME: ideally this should somehow check that we don't have libstdc++
+ return 0;
+}
diff --git a/test/lsan/TestCases/stale_stack_leak.cc b/test/lsan/TestCases/stale_stack_leak.cc
new file mode 100644
index 000000000000..4b8a54edf4cc
--- /dev/null
+++ b/test/lsan/TestCases/stale_stack_leak.cc
@@ -0,0 +1,43 @@
+// Test that out-of-scope local variables are ignored by LSan.
+// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=1"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t 2>&1 | FileCheck %s
+// RUN: LSAN_OPTIONS=$LSAN_BASE":exitcode=0" %run %t 2>&1 | FileCheck --check-prefix=CHECK-sanity %s
+
+#include <stdio.h>
+#include <stdlib.h>
+
+void **pp;
+
+// Put pointer far enough on the stack that LSan has space to run in without
+// overwriting it.
+// Hopefully the argument p will be passed on a register, saving us from false
+// negatives.
+__attribute__((noinline))
+void *PutPointerOnStaleStack(void *p) {
+ void *locals[2048];
+ locals[0] = p;
+ pp = &locals[0];
+ fprintf(stderr, "Test alloc: %p.\n", locals[0]);
+ return 0;
+}
+
+int main() {
+ PutPointerOnStaleStack(malloc(1337));
+ return 0;
+}
+
+// This must run after LSan, to ensure LSan didn't overwrite the pointer before
+// it had a chance to see it. If LSan is invoked with atexit(), this works.
+// Otherwise, we need a different method.
+__attribute__((destructor))
+__attribute__((no_sanitize_address))
+void ConfirmPointerHasSurvived() {
+ fprintf(stderr, "Value after LSan: %p.\n", *pp);
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK-sanity: Test alloc: [[ADDR:.*]].
+// CHECK: LeakSanitizer: detected memory leaks
+// CHECK: [[ADDR]] (1337 bytes)
+// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
+// CHECK-sanity: Value after LSan: [[ADDR]].
diff --git a/test/lsan/TestCases/suppressions_default.cc b/test/lsan/TestCases/suppressions_default.cc
new file mode 100644
index 000000000000..b4c0de016cd1
--- /dev/null
+++ b/test/lsan/TestCases/suppressions_default.cc
@@ -0,0 +1,28 @@
+// RUN: LSAN_BASE="use_registers=0:use_stacks=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sanitizer/lsan_interface.h"
+
+extern "C"
+const char *__lsan_default_suppressions() {
+ return "leak:*LSanTestLeakingFunc*";
+}
+
+void LSanTestLeakingFunc() {
+ void *p = malloc(666);
+ fprintf(stderr, "Test alloc: %p.\n", p);
+}
+
+int main() {
+ LSanTestLeakingFunc();
+ void *q = malloc(1337);
+ fprintf(stderr, "Test alloc: %p.\n", q);
+ return 0;
+}
+// CHECK: Suppressions used:
+// CHECK: 1 666 *LSanTestLeakingFunc*
+// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: 1337 byte(s) leaked in 1 allocation(s)
diff --git a/test/lsan/TestCases/suppressions_file.cc b/test/lsan/TestCases/suppressions_file.cc
new file mode 100644
index 000000000000..16ad9323461e
--- /dev/null
+++ b/test/lsan/TestCases/suppressions_file.cc
@@ -0,0 +1,26 @@
+// RUN: LSAN_BASE="use_registers=0:use_stacks=0"
+// RUN: %clangxx_lsan %s -o %t
+
+// RUN: echo "leak:*LSanTestLeakingFunc*" > %t.supp1
+// RUN: LSAN_OPTIONS=$LSAN_BASE:suppressions=%t.supp1 not %run %t 2>&1 | FileCheck %s
+
+// RUN: echo "leak:%t" > %t.supp2
+// RUN: LSAN_OPTIONS=$LSAN_BASE:suppressions="%t.supp2":symbolize=false %run %t
+
+#include <stdio.h>
+#include <stdlib.h>
+
+void LSanTestLeakingFunc() {
+ void *p = malloc(666);
+ fprintf(stderr, "Test alloc: %p.\n", p);
+}
+
+int main() {
+ LSanTestLeakingFunc();
+ void *q = malloc(1337);
+ fprintf(stderr, "Test alloc: %p.\n", q);
+ return 0;
+}
+// CHECK: Suppressions used:
+// CHECK: 1 666 *LSanTestLeakingFunc*
+// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: 1337 byte(s) leaked in 1 allocation(s)
diff --git a/test/lsan/TestCases/swapcontext.cc b/test/lsan/TestCases/swapcontext.cc
new file mode 100644
index 000000000000..f7e95ed2ca5c
--- /dev/null
+++ b/test/lsan/TestCases/swapcontext.cc
@@ -0,0 +1,47 @@
+// We can't unwind stack if we're running coroutines on heap-allocated
+// memory. Make sure we don't report these leaks.
+
+// RUN: %clangxx_lsan %s -o %t
+// RUN: %run %t 2>&1
+// RUN: not %run %t foo 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#if defined(__APPLE__)
+// Note: ucontext.h is deprecated on OSX, so this test may stop working
+// someday. We define _XOPEN_SOURCE to keep using ucontext.h for now.
+#define _XOPEN_SOURCE 1
+#endif
+#include <ucontext.h>
+#include <unistd.h>
+
+const int kStackSize = 1 << 20;
+
+void Child() {
+ int child_stack;
+ printf("Child: %p\n", &child_stack);
+ int *leaked = new int[666];
+}
+
+int main(int argc, char *argv[]) {
+ char stack_memory[kStackSize + 1];
+ char *heap_memory = new char[kStackSize + 1];
+ char *child_stack = (argc > 1) ? stack_memory : heap_memory;
+
+ printf("Child stack: %p\n", child_stack);
+ ucontext_t orig_context;
+ ucontext_t child_context;
+ getcontext(&child_context);
+ child_context.uc_stack.ss_sp = child_stack;
+ child_context.uc_stack.ss_size = kStackSize / 2;
+ child_context.uc_link = &orig_context;
+ makecontext(&child_context, Child, 0);
+ if (swapcontext(&orig_context, &child_context) < 0) {
+ perror("swapcontext");
+ return 1;
+ }
+
+ delete[] heap_memory;
+ return 0;
+}
+
+// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: 2664 byte(s) leaked in 1 allocation(s)
diff --git a/test/lsan/TestCases/use_after_return.cc b/test/lsan/TestCases/use_after_return.cc
new file mode 100644
index 000000000000..eb917c01ea80
--- /dev/null
+++ b/test/lsan/TestCases/use_after_return.cc
@@ -0,0 +1,23 @@
+// Test that fake stack (introduced by ASan's use-after-return mode) is included
+// in the root set.
+// RUN: LSAN_BASE="report_objects=1:use_registers=0"
+// RUN: %clangxx_lsan %s -O2 -o %t
+// RUN: ASAN_OPTIONS=$ASAN_OPTIONS:detect_stack_use_after_return=1 LSAN_OPTIONS=$LSAN_BASE:"use_stacks=0" not %run %t 2>&1 | FileCheck %s
+// RUN: ASAN_OPTIONS=$ASAN_OPTIONS:detect_stack_use_after_return=1 LSAN_OPTIONS=$LSAN_BASE:"use_stacks=1" %run %t 2>&1
+// RUN: ASAN_OPTIONS=$ASAN_OPTIONS:detect_stack_use_after_return=1 LSAN_OPTIONS="" %run %t 2>&1
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+ void *stack_var = malloc(1337);
+ fprintf(stderr, "Test alloc: %p.\n", stack_var);
+ // Take pointer to variable, to ensure it's not optimized into a register.
+ fprintf(stderr, "Stack var at: %p.\n", &stack_var);
+ // Do not return from main to prevent the pointer from going out of scope.
+ exit(0);
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: LeakSanitizer: detected memory leaks
+// CHECK: [[ADDR]] (1337 bytes)
+// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
diff --git a/test/lsan/TestCases/use_globals_initialized.cc b/test/lsan/TestCases/use_globals_initialized.cc
new file mode 100644
index 000000000000..172d22a9f056
--- /dev/null
+++ b/test/lsan/TestCases/use_globals_initialized.cc
@@ -0,0 +1,21 @@
+// Test that initialized globals are included in the root set.
+// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_globals=0" not %run %t 2>&1 | FileCheck %s
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_globals=1" %run %t 2>&1
+// RUN: LSAN_OPTIONS="" %run %t 2>&1
+
+#include <stdio.h>
+#include <stdlib.h>
+
+void *data_var = (void *)1;
+
+int main() {
+ data_var = malloc(1337);
+ fprintf(stderr, "Test alloc: %p.\n", data_var);
+ return 0;
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: LeakSanitizer: detected memory leaks
+// CHECK: [[ADDR]] (1337 bytes)
+// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
diff --git a/test/lsan/TestCases/use_globals_uninitialized.cc b/test/lsan/TestCases/use_globals_uninitialized.cc
new file mode 100644
index 000000000000..2daa661611f4
--- /dev/null
+++ b/test/lsan/TestCases/use_globals_uninitialized.cc
@@ -0,0 +1,21 @@
+// Test that uninitialized globals are included in the root set.
+// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_globals=0" not %run %t 2>&1 | FileCheck %s
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_globals=1" %run %t 2>&1
+// RUN: LSAN_OPTIONS="" %run %t 2>&1
+
+#include <stdio.h>
+#include <stdlib.h>
+
+void *bss_var;
+
+int main() {
+ bss_var = malloc(1337);
+ fprintf(stderr, "Test alloc: %p.\n", bss_var);
+ return 0;
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: LeakSanitizer: detected memory leaks
+// CHECK: [[ADDR]] (1337 bytes)
+// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
diff --git a/test/lsan/TestCases/use_poisoned_asan.cc b/test/lsan/TestCases/use_poisoned_asan.cc
new file mode 100644
index 000000000000..a1c544c55f28
--- /dev/null
+++ b/test/lsan/TestCases/use_poisoned_asan.cc
@@ -0,0 +1,25 @@
+// ASan-poisoned memory should be ignored if use_poisoned is false.
+// REQUIRES: asan
+// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_poisoned=0" not %run %t 2>&1 | FileCheck %s
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_poisoned=1" %run %t 2>&1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sanitizer/asan_interface.h>
+#include <assert.h>
+
+void **p;
+
+int main() {
+ p = new void *;
+ *p = malloc(1337);
+ fprintf(stderr, "Test alloc: %p.\n", *p);
+ __asan_poison_memory_region(p, sizeof(*p));
+ return 0;
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: LeakSanitizer: detected memory leaks
+// CHECK: [[ADDR]] (1337 bytes)
+// CHECK: SUMMARY: AddressSanitizer:
diff --git a/test/lsan/TestCases/use_registers.cc b/test/lsan/TestCases/use_registers.cc
new file mode 100644
index 000000000000..ce11c3f77bcb
--- /dev/null
+++ b/test/lsan/TestCases/use_registers.cc
@@ -0,0 +1,52 @@
+// Test that registers of running threads are included in the root set.
+// RUN: LSAN_BASE="report_objects=1:use_stacks=0"
+// RUN: %clangxx_lsan -pthread %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_registers=0" not %run %t 2>&1 | FileCheck %s
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_registers=1" %run %t 2>&1
+// RUN: LSAN_OPTIONS="" %run %t 2>&1
+
+#include <assert.h>
+#include <pthread.h>
+#include <sched.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern "C"
+void *registers_thread_func(void *arg) {
+ int *sync = reinterpret_cast<int *>(arg);
+ void *p = malloc(1337);
+ // To store the pointer, choose a register which is unlikely to be reused by
+ // a function call.
+#if defined(__i386__)
+ asm ( "mov %0, %%esi"
+ :
+ : "r" (p)
+ );
+#elif defined(__x86_64__)
+ asm ( "mov %0, %%r15"
+ :
+ : "r" (p)
+ );
+#else
+#error "Test is not supported on this architecture."
+#endif
+ fprintf(stderr, "Test alloc: %p.\n", p);
+ fflush(stderr);
+ __sync_fetch_and_xor(sync, 1);
+ while (true)
+ sched_yield();
+}
+
+int main() {
+ int sync = 0;
+ pthread_t thread_id;
+ int res = pthread_create(&thread_id, 0, registers_thread_func, &sync);
+ assert(res == 0);
+ while (!__sync_fetch_and_xor(&sync, 0))
+ sched_yield();
+ return 0;
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: LeakSanitizer: detected memory leaks
+// CHECK: [[ADDR]] (1337 bytes)
+// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
diff --git a/test/lsan/TestCases/use_stacks.cc b/test/lsan/TestCases/use_stacks.cc
new file mode 100644
index 000000000000..7afcde15c733
--- /dev/null
+++ b/test/lsan/TestCases/use_stacks.cc
@@ -0,0 +1,20 @@
+// Test that stack of main thread is included in the root set.
+// RUN: LSAN_BASE="report_objects=1:use_registers=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_stacks=0" not %run %t 2>&1 | FileCheck %s
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_stacks=1" %run %t 2>&1
+// RUN: LSAN_OPTIONS="" %run %t 2>&1
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+ void *stack_var = malloc(1337);
+ fprintf(stderr, "Test alloc: %p.\n", stack_var);
+ // Do not return from main to prevent the pointer from going out of scope.
+ exit(0);
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: LeakSanitizer: detected memory leaks
+// CHECK: [[ADDR]] (1337 bytes)
+// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
diff --git a/test/lsan/TestCases/use_stacks_threaded.cc b/test/lsan/TestCases/use_stacks_threaded.cc
new file mode 100644
index 000000000000..a1d4383e9569
--- /dev/null
+++ b/test/lsan/TestCases/use_stacks_threaded.cc
@@ -0,0 +1,37 @@
+// Test that stacks of non-main threads are included in the root set.
+// RUN: LSAN_BASE="report_objects=1:use_registers=0"
+// RUN: %clangxx_lsan -pthread %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_stacks=0" not %run %t 2>&1 | FileCheck %s
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_stacks=1" %run %t 2>&1
+// RUN: LSAN_OPTIONS="" %run %t 2>&1
+
+#include <assert.h>
+#include <pthread.h>
+#include <sched.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern "C"
+void *stacks_thread_func(void *arg) {
+ int *sync = reinterpret_cast<int *>(arg);
+ void *p = malloc(1337);
+ fprintf(stderr, "Test alloc: %p.\n", p);
+ fflush(stderr);
+ __sync_fetch_and_xor(sync, 1);
+ while (true)
+ sched_yield();
+}
+
+int main() {
+ int sync = 0;
+ pthread_t thread_id;
+ int res = pthread_create(&thread_id, 0, stacks_thread_func, &sync);
+ assert(res == 0);
+ while (!__sync_fetch_and_xor(&sync, 0))
+ sched_yield();
+ return 0;
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: LeakSanitizer: detected memory leaks
+// CHECK: [[ADDR]] (1337 bytes)
+// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
diff --git a/test/lsan/TestCases/use_tls_dynamic.cc b/test/lsan/TestCases/use_tls_dynamic.cc
new file mode 100644
index 000000000000..860db041ae40
--- /dev/null
+++ b/test/lsan/TestCases/use_tls_dynamic.cc
@@ -0,0 +1,50 @@
+// Test that dynamically allocated TLS space is included in the root set.
+// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
+// RUN: %clangxx %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
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %run %t 2>&1
+// RUN: LSAN_OPTIONS="" %run %t 2>&1
+
+#ifndef BUILD_DSO
+#include <assert.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string>
+
+int main(int argc, char *argv[]) {
+ std::string path = std::string(argv[0]) + "-so.so";
+
+ void *handle = dlopen(path.c_str(), RTLD_LAZY);
+ assert(handle != 0);
+ typedef void **(* store_t)(void *p);
+ store_t StoreToTLS = (store_t)dlsym(handle, "StoreToTLS");
+ assert(dlerror() == 0);
+
+ void *p = malloc(1337);
+ // If we don't know about dynamic TLS, we will return a false leak above.
+ void **p_in_tls = StoreToTLS(p);
+ assert(*p_in_tls == p);
+ fprintf(stderr, "Test alloc: %p.\n", p);
+ return 0;
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: LeakSanitizer: detected memory leaks
+// CHECK: [[ADDR]] (1337 bytes)
+// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
+
+#else // BUILD_DSO
+// A loadable module with a large thread local section, which would require
+// allocation of a new TLS storage chunk when loaded with dlopen(). We use it
+// to test the reachability of such chunks in LSan tests.
+
+// This must be large enough that it doesn't fit into preallocated static TLS
+// space (see STATIC_TLS_SURPLUS in glibc).
+__thread void *huge_thread_local_array[(1 << 20) / sizeof(void *)]; // NOLINT
+
+extern "C" void **StoreToTLS(void *p) {
+ huge_thread_local_array[0] = p;
+ return &huge_thread_local_array[0];
+}
+#endif // BUILD_DSO
diff --git a/test/lsan/TestCases/use_tls_pthread_specific_dynamic.cc b/test/lsan/TestCases/use_tls_pthread_specific_dynamic.cc
new file mode 100644
index 000000000000..14883712e608
--- /dev/null
+++ b/test/lsan/TestCases/use_tls_pthread_specific_dynamic.cc
@@ -0,0 +1,37 @@
+// Test that dynamically allocated thread-specific storage is included in the root set.
+// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %run %t 2>&1
+// RUN: LSAN_OPTIONS="" %run %t 2>&1
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+// From glibc: this many keys are stored in the thread descriptor directly.
+const unsigned PTHREAD_KEY_2NDLEVEL_SIZE = 32;
+
+int main() {
+ static const unsigned kDummyKeysCount = PTHREAD_KEY_2NDLEVEL_SIZE;
+ int res;
+ pthread_key_t dummy_keys[kDummyKeysCount];
+ for (unsigned i = 0; i < kDummyKeysCount; i++) {
+ res = pthread_key_create(&dummy_keys[i], NULL);
+ assert(res == 0);
+ }
+ pthread_key_t key;
+ res = pthread_key_create(&key, NULL);
+ assert(key >= PTHREAD_KEY_2NDLEVEL_SIZE);
+ assert(res == 0);
+ void *p = malloc(1337);
+ res = pthread_setspecific(key, p);
+ assert(res == 0);
+ fprintf(stderr, "Test alloc: %p.\n", p);
+ return 0;
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: LeakSanitizer: detected memory leaks
+// CHECK: [[ADDR]] (1337 bytes)
+// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
diff --git a/test/lsan/TestCases/use_tls_pthread_specific_static.cc b/test/lsan/TestCases/use_tls_pthread_specific_static.cc
new file mode 100644
index 000000000000..1fd5681b6080
--- /dev/null
+++ b/test/lsan/TestCases/use_tls_pthread_specific_static.cc
@@ -0,0 +1,31 @@
+// Test that statically allocated thread-specific storage is included in the root set.
+// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %run %t 2>&1
+// RUN: LSAN_OPTIONS="" %run %t 2>&1
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+// From glibc: this many keys are stored in the thread descriptor directly.
+const unsigned PTHREAD_KEY_2NDLEVEL_SIZE = 32;
+
+int main() {
+ pthread_key_t key;
+ int res;
+ res = pthread_key_create(&key, NULL);
+ assert(res == 0);
+ assert(key < PTHREAD_KEY_2NDLEVEL_SIZE);
+ void *p = malloc(1337);
+ res = pthread_setspecific(key, p);
+ assert(res == 0);
+ fprintf(stderr, "Test alloc: %p.\n", p);
+ return 0;
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: LeakSanitizer: detected memory leaks
+// CHECK: [[ADDR]] (1337 bytes)
+// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
diff --git a/test/lsan/TestCases/use_tls_static.cc b/test/lsan/TestCases/use_tls_static.cc
new file mode 100644
index 000000000000..50db23abb825
--- /dev/null
+++ b/test/lsan/TestCases/use_tls_static.cc
@@ -0,0 +1,21 @@
+// Test that statically allocated TLS space is included in the root set.
+// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %run %t 2>&1
+// RUN: LSAN_OPTIONS="" %run %t 2>&1
+
+#include <stdio.h>
+#include <stdlib.h>
+
+__thread void *tls_var;
+
+int main() {
+ tls_var = malloc(1337);
+ fprintf(stderr, "Test alloc: %p.\n", tls_var);
+ return 0;
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: LeakSanitizer: detected memory leaks
+// CHECK: [[ADDR]] (1337 bytes)
+// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
diff --git a/test/lsan/TestCases/use_unaligned.cc b/test/lsan/TestCases/use_unaligned.cc
new file mode 100644
index 000000000000..3e43ed4c092c
--- /dev/null
+++ b/test/lsan/TestCases/use_unaligned.cc
@@ -0,0 +1,23 @@
+// Test that unaligned pointers are detected correctly.
+// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
+// RUN: %clangxx_lsan %s -o %t
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_unaligned=0" not %run %t 2>&1 | FileCheck %s
+// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_unaligned=1" %run %t 2>&1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void *arr[2];
+
+int main() {
+ void *p = malloc(1337);
+ fprintf(stderr, "Test alloc: %p.\n", p);
+ char *char_arr = (char *)arr;
+ memcpy(char_arr + 1, &p, sizeof(p));
+ return 0;
+}
+// CHECK: Test alloc: [[ADDR:.*]].
+// CHECK: LeakSanitizer: detected memory leaks
+// CHECK: [[ADDR]] (1337 bytes)
+// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer:
diff --git a/test/lsan/lit.common.cfg b/test/lsan/lit.common.cfg
new file mode 100644
index 000000000000..bd1aa2769c42
--- /dev/null
+++ b/test/lsan/lit.common.cfg
@@ -0,0 +1,51 @@
+# -*- Python -*-
+
+# Common configuration for running leak detection tests under LSan/ASan.
+
+import os
+
+def get_required_attr(config, attr_name):
+ attr_value = getattr(config, attr_name, None)
+ if 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 source root.
+config.test_source_root = os.path.dirname(__file__)
+
+# Choose between standalone and LSan+ASan modes.
+lsan_lit_test_mode = get_required_attr(config, 'lsan_lit_test_mode')
+if lsan_lit_test_mode == "Standalone":
+ config.name = "LeakSanitizer-Standalone"
+ lsan_cflags = ["-fsanitize=leak"]
+elif lsan_lit_test_mode == "AddressSanitizer":
+ config.name = "LeakSanitizer-AddressSanitizer"
+ lsan_cflags = ["-fsanitize=address"]
+ config.available_features.add('asan')
+else:
+ lit_config.fatal("Unknown LSan test mode: %r" % lsan_lit_test_mode)
+
+clang_cflags = ["-O0", "-m64"] + 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
+
+config.clang_cflags = clang_cflags
+config.clang_cxxflags = clang_cxxflags
+
+def build_invocation(compile_flags):
+ return " " + " ".join([config.clang] + compile_flags) + " "
+
+config.substitutions.append( ("%clang ", build_invocation(clang_cflags)) )
+config.substitutions.append( ("%clangxx ", build_invocation(clang_cxxflags)) )
+config.substitutions.append( ("%clang_lsan ", build_invocation(clang_lsan_cflags)) )
+config.substitutions.append( ("%clangxx_lsan ", build_invocation(clang_lsan_cxxflags)) )
+
+# LeakSanitizer tests are currently supported on x86-64 Linux only.
+if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64']:
+ config.unsupported = True
+
+config.suffixes = ['.c', '.cc', '.cpp']
diff --git a/test/lsan/lit.site.cfg.in b/test/lsan/lit.site.cfg.in
new file mode 100644
index 000000000000..7d2877bdc528
--- /dev/null
+++ b/test/lsan/lit.site.cfg.in
@@ -0,0 +1,8 @@
+# Load common config for all compiler-rt lit tests.
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")
+
+# Tool-specific config options.
+config.lsan_lit_test_mode = "@LSAN_LIT_TEST_MODE@"
+
+# 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
new file mode 100644
index 000000000000..08786ee777eb
--- /dev/null
+++ b/test/msan/CMakeLists.txt
@@ -0,0 +1,23 @@
+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_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS})
+if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND MSAN_TEST_DEPS msan)
+endif()
+
+if(COMPILER_RT_INCLUDE_TESTS AND COMPILER_RT_HAS_LIBCXX_SOURCES)
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg)
+ list(APPEND MSAN_TEST_DEPS MsanUnitTests)
+endif()
+
+add_lit_testsuite(check-msan "Running the MemorySanitizer tests"
+ ${CMAKE_CURRENT_BINARY_DIR}
+ DEPENDS ${MSAN_TEST_DEPS}
+ )
+set_target_properties(check-msan PROPERTIES FOLDER "MSan tests")
diff --git a/test/msan/Linux/getresid.cc b/test/msan/Linux/getresid.cc
new file mode 100644
index 000000000000..385351dfdcde
--- /dev/null
+++ b/test/msan/Linux/getresid.cc
@@ -0,0 +1,25 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p 2>&1
+// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p 2>&1
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p 2>&1
+
+#include <assert.h>
+#include <unistd.h>
+
+#include <sanitizer/msan_interface.h>
+
+int main(int argc, char *argv[]) {
+ uid_t uids[6];
+ assert(0 == __msan_test_shadow(uids, 6 * sizeof(uid_t)));
+ assert(0 == getresuid(&uids[0], &uids[2], &uids[4]));
+ for (int i = 0; i < 3; i++)
+ assert(sizeof(uid_t) ==
+ __msan_test_shadow(uids + 2 * i, 2 * sizeof(uid_t)));
+
+ gid_t gids[6];
+ assert(0 == __msan_test_shadow(gids, 6 * sizeof(gid_t)));
+ assert(0 == getresgid(&gids[0], &gids[2], &gids[4]));
+ for (int i = 0; i < 3; i++)
+ assert(sizeof(gid_t) ==
+ __msan_test_shadow(gids + 2 * i, 2 * sizeof(gid_t)));
+ return 0;
+}
diff --git a/test/msan/Linux/glob.cc b/test/msan/Linux/glob.cc
new file mode 100644
index 000000000000..8604e4d76265
--- /dev/null
+++ b/test/msan/Linux/glob.cc
@@ -0,0 +1,27 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p 2>&1 | FileCheck %s
+// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p 2>&1 | FileCheck %s
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <glob.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+int main(int argc, char *argv[]) {
+ assert(argc == 2);
+ char buf[1024];
+ snprintf(buf, sizeof(buf), "%s/%s", argv[1], "glob_test_root/*a");
+
+ glob_t globbuf;
+ int res = glob(buf, 0, 0, &globbuf);
+
+ printf("%d %s\n", errno, strerror(errno));
+ assert(res == 0);
+ assert(globbuf.gl_pathc == 2);
+ printf("%zu\n", strlen(globbuf.gl_pathv[0]));
+ printf("%zu\n", strlen(globbuf.gl_pathv[1]));
+ printf("PASS\n");
+ // CHECK: PASS
+ return 0;
+}
diff --git a/test/msan/Linux/glob_altdirfunc.cc b/test/msan/Linux/glob_altdirfunc.cc
new file mode 100644
index 000000000000..2c02e735e05e
--- /dev/null
+++ b/test/msan/Linux/glob_altdirfunc.cc
@@ -0,0 +1,78 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p 2>&1 | FileCheck %s
+// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p 2>&1 | FileCheck %s
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <glob.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#include <sanitizer/msan_interface.h>
+
+static void my_gl_closedir(void *dir) {
+ if (!dir)
+ exit(1);
+ closedir((DIR *)dir);
+}
+
+static struct dirent *my_gl_readdir(void *dir) {
+ if (!dir)
+ exit(1);
+ struct dirent *d = readdir((DIR *)dir);
+ if (d) __msan_poison(d, d->d_reclen); // hehe
+ return d;
+}
+
+static void *my_gl_opendir(const char *s) {
+ assert(__msan_test_shadow(s, strlen(s) + 1) == (size_t)-1);
+ return opendir(s);
+}
+
+static int my_gl_lstat(const char *s, struct stat *st) {
+ assert(__msan_test_shadow(s, strlen(s) + 1) == (size_t)-1);
+ if (!st)
+ exit(1);
+ return lstat(s, st);
+}
+
+static int my_gl_stat(const char *s, struct stat *st) {
+ assert(__msan_test_shadow(s, strlen(s) + 1) == (size_t)-1);
+ if (!st)
+ exit(1);
+ return lstat(s, st);
+}
+
+int main(int argc, char *argv[]) {
+ assert(argc == 2);
+ char buf[1024];
+ snprintf(buf, sizeof(buf), "%s/%s", argv[1], "glob_test_root/*a");
+
+ glob_t globbuf;
+ globbuf.gl_closedir = my_gl_closedir;
+ globbuf.gl_readdir = my_gl_readdir;
+ globbuf.gl_opendir = my_gl_opendir;
+ globbuf.gl_lstat = my_gl_lstat;
+ globbuf.gl_stat = my_gl_stat;
+ for (int i = 0; i < 10000; ++i) {
+ int res = glob(buf, GLOB_ALTDIRFUNC | GLOB_MARK, 0, &globbuf);
+ assert(res == 0);
+ printf("%d %s\n", errno, strerror(errno));
+ assert(globbuf.gl_pathc == 2);
+ printf("%zu\n", strlen(globbuf.gl_pathv[0]));
+ printf("%zu\n", strlen(globbuf.gl_pathv[1]));
+ __msan_poison(globbuf.gl_pathv[0], strlen(globbuf.gl_pathv[0]) + 1);
+ __msan_poison(globbuf.gl_pathv[1], strlen(globbuf.gl_pathv[1]) + 1);
+ globfree(&globbuf);
+ }
+
+ printf("PASS\n");
+ // CHECK: PASS
+ return 0;
+}
diff --git a/test/msan/Linux/glob_nomatch.cc b/test/msan/Linux/glob_nomatch.cc
new file mode 100644
index 000000000000..bc35c30d6d07
--- /dev/null
+++ b/test/msan/Linux/glob_nomatch.cc
@@ -0,0 +1,21 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p
+
+#include <assert.h>
+#include <glob.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char *argv[]) {
+ assert(argc == 2);
+ char buf[1024];
+ snprintf(buf, sizeof(buf), "%s/%s", argv[1], "glob_test_root/*c");
+
+ glob_t globbuf;
+ int res = glob(buf, 0, 0, &globbuf);
+ assert(res == GLOB_NOMATCH);
+ assert(globbuf.gl_pathc == 0);
+ if (globbuf.gl_pathv == 0)
+ exit(0);
+ return 0;
+}
diff --git a/test/msan/Linux/glob_test_root/aa b/test/msan/Linux/glob_test_root/aa
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/msan/Linux/glob_test_root/aa
diff --git a/test/msan/Linux/glob_test_root/ab b/test/msan/Linux/glob_test_root/ab
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/msan/Linux/glob_test_root/ab
diff --git a/test/msan/Linux/glob_test_root/ba b/test/msan/Linux/glob_test_root/ba
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/msan/Linux/glob_test_root/ba
diff --git a/test/msan/Linux/lit.local.cfg b/test/msan/Linux/lit.local.cfg
new file mode 100644
index 000000000000..57271b8078a4
--- /dev/null
+++ b/test/msan/Linux/lit.local.cfg
@@ -0,0 +1,9 @@
+def getRoot(config):
+ if not config.parent:
+ return config
+ return getRoot(config.parent)
+
+root = getRoot(config)
+
+if root.host_os not in ['Linux']:
+ config.unsupported = True
diff --git a/test/msan/Linux/sunrpc.cc b/test/msan/Linux/sunrpc.cc
new file mode 100644
index 000000000000..78645a7dcbf2
--- /dev/null
+++ b/test/msan/Linux/sunrpc.cc
@@ -0,0 +1,40 @@
+// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=int -DFN=xdr_int %s -o %t && \
+// RUN: %run %t 2>&1
+// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=int -DFN=xdr_int -DUNINIT=1 %s -o %t && \
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=double -DFN=xdr_double %s -o %t && \
+// RUN: %run %t 2>&1
+// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=double -DFN=xdr_double -DUNINIT=1 %s -o %t && \
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=u_quad_t -DFN=xdr_u_longlong_t %s -o %t && \
+// RUN: %run %t 2>&1
+// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=u_quad_t -DFN=xdr_u_longlong_t -DUNINIT=1 %s -o %t && \
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <rpc/xdr.h>
+
+#include <sanitizer/msan_interface.h>
+
+int main(int argc, char *argv[]) {
+ XDR xdrs;
+ char buf[100];
+ xdrmem_create(&xdrs, buf, sizeof(buf), XDR_ENCODE);
+ TYPE x;
+#ifndef UNINIT
+ x = 42;
+#endif
+ bool_t res = FN(&xdrs, &x);
+ // CHECK: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: {{in main.*sunrpc.cc:}}[[@LINE-2]]
+ assert(res == TRUE);
+ xdr_destroy(&xdrs);
+
+ xdrmem_create(&xdrs, buf, sizeof(buf), XDR_DECODE);
+ TYPE y;
+ res = FN(&xdrs, &y);
+ assert(res == TRUE);
+ assert(__msan_test_shadow(&y, sizeof(y)) == -1);
+ xdr_destroy(&xdrs);
+ return 0;
+}
diff --git a/test/msan/Linux/sunrpc_bytes.cc b/test/msan/Linux/sunrpc_bytes.cc
new file mode 100644
index 000000000000..f0c35746f34d
--- /dev/null
+++ b/test/msan/Linux/sunrpc_bytes.cc
@@ -0,0 +1,38 @@
+// RUN: %clangxx_msan -m64 -g -O0 %s -o %t && \
+// RUN: %run %t 2>&1
+// RUN: %clangxx_msan -m64 -g -O0 -DUNINIT=1 %s -o %t && \
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <string.h>
+#include <rpc/xdr.h>
+
+#include <sanitizer/msan_interface.h>
+
+int main(int argc, char *argv[]) {
+ XDR xdrs;
+ char buf[100];
+ xdrmem_create(&xdrs, buf, sizeof(buf), XDR_ENCODE);
+ char s[20];
+#ifndef UNINIT
+ strcpy(s, "hello");
+#endif
+ char *sp = s;
+ unsigned sz = 6;
+ bool_t res = xdr_bytes(&xdrs, &sp, &sz, sizeof(s));
+ // CHECK: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: {{in main.*sunrpc_bytes.cc:}}[[@LINE-2]]
+ assert(res == TRUE);
+ xdr_destroy(&xdrs);
+
+ xdrmem_create(&xdrs, buf, sizeof(buf), XDR_DECODE);
+ char s2[20];
+ char *sp2 = s2;
+ unsigned sz2;
+ res = xdr_bytes(&xdrs, &sp2, &sz2, sizeof(s2));
+ assert(res == TRUE);
+ assert(sz == sz2);
+ assert(strcmp(s, s2) == 0);
+ xdr_destroy(&xdrs);
+ return 0;
+}
diff --git a/test/msan/Linux/sunrpc_string.cc b/test/msan/Linux/sunrpc_string.cc
new file mode 100644
index 000000000000..3f44a96d114c
--- /dev/null
+++ b/test/msan/Linux/sunrpc_string.cc
@@ -0,0 +1,35 @@
+// RUN: %clangxx_msan -m64 -g -O0 %s -o %t && \
+// RUN: %run %t 2>&1
+// RUN: %clangxx_msan -m64 -g -O0 -DUNINIT=1 %s -o %t && \
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <string.h>
+#include <rpc/xdr.h>
+
+#include <sanitizer/msan_interface.h>
+
+int main(int argc, char *argv[]) {
+ XDR xdrs;
+ char buf[100];
+ xdrmem_create(&xdrs, buf, sizeof(buf), XDR_ENCODE);
+ char s[20];
+#ifndef UNINIT
+ strcpy(s, "hello");
+#endif
+ char *sp = s;
+ bool_t res = xdr_string(&xdrs, &sp, sizeof(s));
+ // CHECK: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: {{in main.*sunrpc_string.cc:}}[[@LINE-2]]
+ assert(res == TRUE);
+ xdr_destroy(&xdrs);
+
+ xdrmem_create(&xdrs, buf, sizeof(buf), XDR_DECODE);
+ char s2[20];
+ char *sp2 = s2;
+ res = xdr_string(&xdrs, &sp2, sizeof(s2));
+ assert(res == TRUE);
+ assert(strcmp(s, s2) == 0);
+ xdr_destroy(&xdrs);
+ return 0;
+}
diff --git a/test/msan/Linux/syscalls.cc b/test/msan/Linux/syscalls.cc
new file mode 100644
index 000000000000..4dd97e745148
--- /dev/null
+++ b/test/msan/Linux/syscalls.cc
@@ -0,0 +1,115 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t 2>&1
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t 2>&1
+
+#include <assert.h>
+#include <errno.h>
+#include <glob.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <linux/aio_abi.h>
+#include <sys/ptrace.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+
+#include <sanitizer/linux_syscall_hooks.h>
+#include <sanitizer/msan_interface.h>
+
+/* Test the presence of __sanitizer_syscall_ in the tool runtime, and general
+ sanity of their behaviour. */
+
+int main(int argc, char *argv[]) {
+ char buf[1000];
+ const int kTen = 10;
+ const int kFortyTwo = 42;
+ memset(buf, 0, sizeof(buf));
+ __msan_unpoison(buf, sizeof(buf));
+ __sanitizer_syscall_pre_recvmsg(0, buf, 0);
+ __sanitizer_syscall_pre_rt_sigpending(buf, kTen);
+ __sanitizer_syscall_pre_getdents(0, buf, kTen);
+ __sanitizer_syscall_pre_getdents64(0, buf, kTen);
+
+ __msan_unpoison(buf, sizeof(buf));
+ __sanitizer_syscall_post_recvmsg(0, 0, buf, 0);
+ __sanitizer_syscall_post_rt_sigpending(-1, buf, kTen);
+ __sanitizer_syscall_post_getdents(0, 0, buf, kTen);
+ __sanitizer_syscall_post_getdents64(0, 0, buf, kTen);
+ assert(__msan_test_shadow(buf, sizeof(buf)) == -1);
+
+ __msan_unpoison(buf, sizeof(buf));
+ __sanitizer_syscall_post_recvmsg(kTen, 0, buf, 0);
+
+ // Tell the kernel that the output struct size is 10 bytes, verify that those
+ // bytes are unpoisoned, and the next byte is not.
+ __msan_poison(buf, kTen + 1);
+ __sanitizer_syscall_post_rt_sigpending(0, buf, kTen);
+ assert(__msan_test_shadow(buf, sizeof(buf)) == kTen);
+
+ __msan_poison(buf, kTen + 1);
+ __sanitizer_syscall_post_getdents(kTen, 0, buf, kTen);
+ assert(__msan_test_shadow(buf, sizeof(buf)) == kTen);
+
+ __msan_poison(buf, kTen + 1);
+ __sanitizer_syscall_post_getdents64(kTen, 0, buf, kTen);
+ assert(__msan_test_shadow(buf, sizeof(buf)) == kTen);
+
+ __msan_poison(buf, sizeof(buf));
+ __sanitizer_syscall_post_clock_getres(0, 0, buf);
+ assert(__msan_test_shadow(buf, sizeof(buf)) == sizeof(long) * 2);
+
+ __msan_poison(buf, sizeof(buf));
+ __sanitizer_syscall_post_clock_gettime(0, 0, buf);
+ assert(__msan_test_shadow(buf, sizeof(buf)) == sizeof(long) * 2);
+
+ // Failed syscall does not write to the buffer.
+ __msan_poison(buf, sizeof(buf));
+ __sanitizer_syscall_post_clock_gettime(-1, 0, buf);
+ assert(__msan_test_shadow(buf, sizeof(buf)) == 0);
+
+ __msan_poison(buf, sizeof(buf));
+ __sanitizer_syscall_post_read(5, 42, buf, 10);
+ assert(__msan_test_shadow(buf, sizeof(buf)) == 5);
+
+ __msan_poison(buf, sizeof(buf));
+ __sanitizer_syscall_post_newfstatat(0, 5, "/path/to/file", buf, 0);
+ assert(__msan_test_shadow(buf, sizeof(buf)) == sizeof(struct stat));
+
+ __msan_poison(buf, sizeof(buf));
+ int prio = 0;
+ __sanitizer_syscall_post_mq_timedreceive(kFortyTwo, 5, buf, sizeof(buf), &prio, 0);
+ assert(__msan_test_shadow(buf, sizeof(buf)) == kFortyTwo);
+ assert(__msan_test_shadow(&prio, sizeof(prio)) == -1);
+
+ __msan_poison(buf, sizeof(buf));
+ __sanitizer_syscall_post_ptrace(0, PTRACE_PEEKUSER, kFortyTwo, 0xABCD, buf);
+ assert(__msan_test_shadow(buf, sizeof(buf)) == sizeof(void *));
+
+ __msan_poison(buf, sizeof(buf));
+ struct iocb iocb[3];
+ struct iocb *iocbp[3] = { &iocb[0], &iocb[1], &iocb[2] };
+ memset(iocb, 0, sizeof(iocb));
+ iocb[0].aio_lio_opcode = IOCB_CMD_PREAD;
+ iocb[0].aio_buf = (__u64)buf;
+ iocb[0].aio_nbytes = 10;
+ iocb[1].aio_lio_opcode = IOCB_CMD_PREAD;
+ iocb[1].aio_buf = (__u64)(&buf[20]);
+ iocb[1].aio_nbytes = 15;
+ struct iovec vec[2] = { {&buf[40], 3}, {&buf[50], 20} };
+ iocb[2].aio_lio_opcode = IOCB_CMD_PREADV;
+ iocb[2].aio_buf = (__u64)(&vec);
+ iocb[2].aio_nbytes = 2;
+ __sanitizer_syscall_pre_io_submit(0, 3, &iocbp);
+ assert(__msan_test_shadow(buf, sizeof(buf)) == 10);
+ assert(__msan_test_shadow(buf + 20, sizeof(buf) - 20) == 15);
+ assert(__msan_test_shadow(buf + 40, sizeof(buf) - 40) == 3);
+ assert(__msan_test_shadow(buf + 50, sizeof(buf) - 50) == 20);
+
+ __msan_poison(buf, sizeof(buf));
+ char *p = buf;
+ __msan_poison(&p, sizeof(p));
+ __sanitizer_syscall_post_io_setup(0, 1, &p);
+ assert(__msan_test_shadow(&p, sizeof(p)) == -1);
+ assert(__msan_test_shadow(buf, sizeof(buf)) >= 32);
+
+ return 0;
+}
diff --git a/test/msan/Linux/tcgetattr.cc b/test/msan/Linux/tcgetattr.cc
new file mode 100644
index 000000000000..e1425b84f550
--- /dev/null
+++ b/test/msan/Linux/tcgetattr.cc
@@ -0,0 +1,21 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p
+
+#include <assert.h>
+#include <glob.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[]) {
+ int fd = getpt();
+ assert(fd >= 0);
+
+ struct termios t;
+ int res = tcgetattr(fd, &t);
+ assert(!res);
+
+ if (t.c_iflag == 0)
+ exit(0);
+ return 0;
+}
diff --git a/test/msan/Linux/xattr.cc b/test/msan/Linux/xattr.cc
new file mode 100644
index 000000000000..1beba117d574
--- /dev/null
+++ b/test/msan/Linux/xattr.cc
@@ -0,0 +1,145 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p 2>&1
+// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p 2>&1
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p 2>&1
+
+#include <argz.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sanitizer/msan_interface.h>
+
+// Do not depend on libattr headers.
+#ifndef ENOATTR
+#define ENOATTR ENODATA
+#endif
+
+extern "C" {
+ssize_t listxattr(const char *path, char *list, size_t size);
+ssize_t llistxattr(const char *path, char *list, size_t size);
+ssize_t flistxattr(int fd, char *list, size_t size);
+ssize_t getxattr(const char *path, const char *name, void *value, size_t size);
+ssize_t lgetxattr(const char *path, const char *name, void *value, size_t size);
+ssize_t fgetxattr(int fd, const char *name, void *value, size_t size);
+}
+
+char g_path[1024];
+int g_fd;
+
+// Life before closures...
+ssize_t listxattr_wrapper(char *buf, size_t size) {
+ return listxattr(g_path, buf, size);
+}
+
+ssize_t llistxattr_wrapper(char *buf, size_t size) {
+ return llistxattr(g_path, buf, size);
+}
+
+ssize_t flistxattr_wrapper(char *buf, size_t size) {
+ return flistxattr(g_fd, buf, size);
+}
+
+ssize_t getxattr_wrapper(const char *name, char *buf, size_t size) {
+ return getxattr(g_path, name, buf, size);
+}
+
+ssize_t lgetxattr_wrapper(const char *name, char *buf, size_t size) {
+ return lgetxattr(g_path, name, buf, size);
+}
+
+ssize_t fgetxattr_wrapper(const char *name, char *buf, size_t size) {
+ return fgetxattr(g_fd, name, buf, size);
+}
+
+size_t test_list(ssize_t fun(char*, size_t), char **buf) {
+ int buf_size = 1024;
+ while (true) {
+ *buf = (char *)malloc(buf_size);
+ assert(__msan_test_shadow(*buf, buf_size) != -1);
+ ssize_t res = fun(*buf, buf_size);
+ if (res >= 0) {
+ assert(__msan_test_shadow(*buf, buf_size) == res);
+ return res;
+ }
+ if (errno == ENOTSUP) {
+ printf("Extended attributes are disabled. *xattr test is a no-op.\n");
+ exit(0);
+ }
+ assert(errno == ERANGE);
+ free(*buf);
+ buf_size *= 2;
+ }
+}
+
+// True means success. False means result inconclusive because we don't have
+// access to this attribute.
+bool test_get_single_attr(ssize_t fun(const char *, char *, size_t),
+ const char *attr_name) {
+ char *buf;
+ int buf_size = 1024;
+ while (true) {
+ buf = (char *)malloc(buf_size);
+ assert(__msan_test_shadow(buf, buf_size) != -1);
+ ssize_t res = fun(attr_name, buf, buf_size);
+ if (res >= 0) {
+ assert(__msan_test_shadow(buf, buf_size) == res);
+ free(buf);
+ return true;
+ }
+ if (errno == ENOTSUP) {
+ printf("Extended attributes are disabled. *xattr test is a no-op.\n");
+ exit(0);
+ }
+ if (errno == ENOATTR)
+ return false;
+ assert(errno == ERANGE);
+ free(buf);
+ buf_size *= 2;
+ }
+}
+
+void test_get(ssize_t fun(const char *, char *, size_t), const char *attr_list,
+ size_t attr_list_size) {
+ // Try every attribute, until we see one we can access. Attribute names are
+ // null-separated strings in attr_list.
+ size_t attr_list_len = argz_count(attr_list, attr_list_size);
+ size_t argv_size = (attr_list_len + 1) * sizeof(char *);
+ char **attrs = (char **)malloc(argv_size);
+ argz_extract(attr_list, attr_list_size, attrs);
+ // TODO(smatveev): we need proper argz_* interceptors
+ __msan_unpoison(attrs, argv_size);
+ for (size_t i = 0; (i < attr_list_len) && attrs[i]; i++) {
+ if (test_get_single_attr(fun, attrs[i]))
+ return;
+ }
+ printf("*xattr test could not access any attributes.\n");
+}
+
+// TODO: set some attributes before trying to retrieve them with *getxattr.
+// Currently the list is empty, so *getxattr is not tested.
+int main(int argc, char *argv[]) {
+ assert(argc == 2);
+ snprintf(g_path, sizeof(g_path), "%s/%s", argv[1], "xattr_test_root/a");
+
+ g_fd = open(g_path, O_RDONLY);
+ assert(g_fd);
+
+ char *attr_list;
+ size_t attr_list_size;
+ attr_list_size = test_list(listxattr_wrapper, &attr_list);
+ free(attr_list);
+ attr_list_size = test_list(llistxattr_wrapper, &attr_list);
+ free(attr_list);
+ attr_list_size = test_list(flistxattr_wrapper, &attr_list);
+
+ test_get(getxattr_wrapper, attr_list, attr_list_size);
+ test_get(lgetxattr_wrapper, attr_list, attr_list_size);
+ test_get(fgetxattr_wrapper, attr_list, attr_list_size);
+
+ free(attr_list);
+ return 0;
+}
diff --git a/test/msan/Linux/xattr_test_root/a b/test/msan/Linux/xattr_test_root/a
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/msan/Linux/xattr_test_root/a
diff --git a/test/msan/Unit/lit.site.cfg.in b/test/msan/Unit/lit.site.cfg.in
new file mode 100644
index 000000000000..dc0e9613d59e
--- /dev/null
+++ b/test/msan/Unit/lit.site.cfg.in
@@ -0,0 +1,14 @@
+## Autogenerated by LLVM/Clang configuration.
+# Do not edit!
+
+# Load common config for all compiler-rt unit tests.
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/unittests/lit.common.unit.configured")
+
+# Setup config name.
+config.name = 'MemorySanitizer-Unit'
+
+# Setup test source and exec root. For unit tests, we define
+# it as build directory with MSan unit tests.
+# FIXME: Don't use hardcoded path to MSan unit tests.
+config.test_exec_root = "@COMPILER_RT_BINARY_DIR@/lib/msan/tests"
+config.test_source_root = config.test_exec_root
diff --git a/test/msan/allocator_returns_null.cc b/test/msan/allocator_returns_null.cc
new file mode 100644
index 000000000000..f4ea51d58872
--- /dev/null
+++ b/test/msan/allocator_returns_null.cc
@@ -0,0 +1,81 @@
+// Test the behavior of malloc/calloc/realloc when the allocation size is huge.
+// By default (allocator_may_return_null=0) the process should crash.
+// With allocator_may_return_null=1 the allocator should return 0.
+//
+// RUN: %clangxx_msan -O0 %s -o %t
+// RUN: not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
+// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
+// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mNULL
+// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cCRASH
+// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cNULL
+// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coCRASH
+// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coNULL
+// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rCRASH
+// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rNULL
+// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrCRASH
+// RUN: MSAN_OPTIONS=allocator_may_return_null=1 %run %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrNULL
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <limits>
+int main(int argc, char **argv) {
+ volatile size_t size = std::numeric_limits<size_t>::max() - 10000;
+ assert(argc == 2);
+ char *x = 0;
+ if (!strcmp(argv[1], "malloc")) {
+ fprintf(stderr, "malloc:\n");
+ x = (char*)malloc(size);
+ }
+ if (!strcmp(argv[1], "calloc")) {
+ fprintf(stderr, "calloc:\n");
+ x = (char*)calloc(size / 4, 4);
+ }
+
+ if (!strcmp(argv[1], "calloc-overflow")) {
+ fprintf(stderr, "calloc-overflow:\n");
+ volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max();
+ size_t kArraySize = 4096;
+ volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
+ x = (char*)calloc(kArraySize, kArraySize2);
+ }
+
+ if (!strcmp(argv[1], "realloc")) {
+ fprintf(stderr, "realloc:\n");
+ x = (char*)realloc(0, size);
+ }
+ if (!strcmp(argv[1], "realloc-after-malloc")) {
+ fprintf(stderr, "realloc-after-malloc:\n");
+ char *t = (char*)malloc(100);
+ *t = 42;
+ x = (char*)realloc(t, size);
+ assert(*t == 42);
+ }
+ // The NULL pointer is printed differently on different systems, while (long)0
+ // is always the same.
+ fprintf(stderr, "x: %lx\n", (long)x);
+ return x != 0;
+}
+// CHECK-mCRASH: malloc:
+// CHECK-mCRASH: MemorySanitizer's allocator is terminating the process
+// CHECK-cCRASH: calloc:
+// CHECK-cCRASH: MemorySanitizer's allocator is terminating the process
+// CHECK-coCRASH: calloc-overflow:
+// CHECK-coCRASH: MemorySanitizer's allocator is terminating the process
+// CHECK-rCRASH: realloc:
+// CHECK-rCRASH: MemorySanitizer's allocator is terminating the process
+// CHECK-mrCRASH: realloc-after-malloc:
+// CHECK-mrCRASH: MemorySanitizer's allocator is terminating the process
+
+// CHECK-mNULL: malloc:
+// CHECK-mNULL: x: 0
+// CHECK-cNULL: calloc:
+// CHECK-cNULL: x: 0
+// CHECK-coNULL: calloc-overflow:
+// CHECK-coNULL: x: 0
+// CHECK-rNULL: realloc:
+// CHECK-rNULL: x: 0
+// CHECK-mrNULL: realloc-after-malloc:
+// CHECK-mrNULL: x: 0
diff --git a/test/msan/backtrace.cc b/test/msan/backtrace.cc
new file mode 100644
index 000000000000..473e0ae8f88b
--- /dev/null
+++ b/test/msan/backtrace.cc
@@ -0,0 +1,26 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t
+
+#include <assert.h>
+#include <execinfo.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+__attribute__((noinline))
+void f() {
+ void *buf[10];
+ int sz = backtrace(buf, sizeof(buf) / sizeof(*buf));
+ assert(sz > 0);
+ for (int i = 0; i < sz; ++i)
+ if (!buf[i])
+ exit(1);
+ char **s = backtrace_symbols(buf, sz);
+ assert(s > 0);
+ for (int i = 0; i < sz; ++i)
+ printf("%d\n", strlen(s[i]));
+}
+
+int main(void) {
+ f();
+ return 0;
+}
diff --git a/test/msan/c-strdup.c b/test/msan/c-strdup.c
new file mode 100644
index 000000000000..059300e4205a
--- /dev/null
+++ b/test/msan/c-strdup.c
@@ -0,0 +1,17 @@
+// RUN: %clang_msan -m64 -O0 %s -o %t && %run %t >%t.out 2>&1
+// RUN: %clang_msan -m64 -O1 %s -o %t && %run %t >%t.out 2>&1
+// RUN: %clang_msan -m64 -O2 %s -o %t && %run %t >%t.out 2>&1
+// RUN: %clang_msan -m64 -O3 %s -o %t && %run %t >%t.out 2>&1
+
+// Test that strdup in C programs is intercepted.
+// GLibC headers translate strdup to __strdup at -O1 and higher.
+
+#include <stdlib.h>
+#include <string.h>
+int main(int argc, char **argv) {
+ char buf[] = "abc";
+ char *p = strdup(buf);
+ if (*p)
+ exit(0);
+ return 0;
+}
diff --git a/test/msan/chained_origin.cc b/test/msan/chained_origin.cc
new file mode 100644
index 000000000000..336bbd852cb3
--- /dev/null
+++ b/test/msan/chained_origin.cc
@@ -0,0 +1,66 @@
+// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t && \
+// RUN: not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-STACK < %t.out
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -DHEAP=1 -m64 -O3 %s -o %t && \
+// RUN: not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-HEAP < %t.out
+
+
+// RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t && \
+// RUN: not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-STACK < %t.out
+
+// RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -DHEAP=1 -m64 -O3 %s -o %t && \
+// RUN: not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-HEAP < %t.out
+
+
+#include <stdio.h>
+
+volatile int x, y;
+
+__attribute__((noinline))
+void fn_g(int a) {
+ x = a;
+}
+
+__attribute__((noinline))
+void fn_f(int a) {
+ fn_g(a);
+}
+
+__attribute__((noinline))
+void fn_h() {
+ y = x;
+}
+
+int main(int argc, char *argv[]) {
+#ifdef HEAP
+ int * volatile zz = new int;
+ int z = *zz;
+#else
+ int volatile z;
+#endif
+ fn_f(z);
+ fn_h();
+ return y;
+}
+
+// CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+// CHECK: {{#0 .* in main.*chained_origin.cc:47}}
+
+// CHECK: Uninitialized value was stored to memory at
+// CHECK: {{#0 .* in fn_h.*chained_origin.cc:35}}
+// CHECK: {{#1 .* in main.*chained_origin.cc:46}}
+
+// CHECK: Uninitialized value was stored to memory at
+// CHECK: {{#0 .* in fn_g.*chained_origin.cc:25}}
+// CHECK: {{#1 .* in fn_f.*chained_origin.cc:30}}
+// CHECK: {{#2 .* in main.*chained_origin.cc:45}}
+
+// CHECK-STACK: Uninitialized value was created by an allocation of 'z' in the stack frame of function 'main'
+// CHECK-STACK: {{#0 .* in main.*chained_origin.cc:38}}
+
+// CHECK-HEAP: Uninitialized value was created by a heap allocation
+// CHECK-HEAP: {{#1 .* in main.*chained_origin.cc:40}}
diff --git a/test/msan/chained_origin_empty_stack.cc b/test/msan/chained_origin_empty_stack.cc
new file mode 100644
index 000000000000..36727e3d7aa7
--- /dev/null
+++ b/test/msan/chained_origin_empty_stack.cc
@@ -0,0 +1,34 @@
+// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t && \
+// RUN: MSAN_OPTIONS=store_context_size=1 not %run %t 2>&1 | FileCheck %s
+
+// Test that stack trace for the intermediate store is not empty.
+
+// CHECK: MemorySanitizer: use-of-uninitialized-value
+// CHECK: #0 {{.*}} in main
+
+// CHECK: Uninitialized value was stored to memory at
+// CHECK: #0 {{.*}} in fn_g
+// CHECK-NOT: #1
+
+// CHECK: Uninitialized value was created by an allocation of 'z' in the stack frame of function 'main'
+// CHECK: #0 {{.*}} in main
+
+#include <stdio.h>
+
+volatile int x;
+
+__attribute__((noinline))
+void fn_g(int a) {
+ x = a;
+}
+
+__attribute__((noinline))
+void fn_f(int a) {
+ fn_g(a);
+}
+
+int main(int argc, char *argv[]) {
+ int volatile z;
+ fn_f(z);
+ return x;
+}
diff --git a/test/msan/chained_origin_limits.cc b/test/msan/chained_origin_limits.cc
new file mode 100644
index 000000000000..0cc57f32a6ac
--- /dev/null
+++ b/test/msan/chained_origin_limits.cc
@@ -0,0 +1,178 @@
+// This test program creates a very large number of unique histories.
+
+// Heap origin.
+// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t
+
+// RUN: MSAN_OPTIONS=origin_history_size=7 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK7 < %t.out
+
+// RUN: MSAN_OPTIONS=origin_history_size=2 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK2 < %t.out
+
+// RUN: MSAN_OPTIONS=origin_history_per_stack_limit=1 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK-PER-STACK < %t.out
+
+// RUN: MSAN_OPTIONS=origin_history_size=7,origin_history_per_stack_limit=0 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK7 < %t.out
+
+// Stack origin.
+// RUN: %clangxx_msan -DSTACK -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t
+
+// RUN: MSAN_OPTIONS=origin_history_size=7 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK7 < %t.out
+
+// RUN: MSAN_OPTIONS=origin_history_size=2 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK2 < %t.out
+
+// RUN: MSAN_OPTIONS=origin_history_per_stack_limit=1 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK-PER-STACK < %t.out
+
+// RUN: MSAN_OPTIONS=origin_history_size=7,origin_history_per_stack_limit=0 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK7 < %t.out
+
+
+// Heap origin, with calls.
+// RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t
+
+// RUN: MSAN_OPTIONS=origin_history_size=7 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK7 < %t.out
+
+// RUN: MSAN_OPTIONS=origin_history_size=2 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK2 < %t.out
+
+// RUN: MSAN_OPTIONS=origin_history_per_stack_limit=1 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK-PER-STACK < %t.out
+
+// RUN: MSAN_OPTIONS=origin_history_size=7,origin_history_per_stack_limit=0 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK7 < %t.out
+
+
+// Stack origin, with calls.
+// RUN: %clangxx_msan -DSTACK -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t
+
+// RUN: MSAN_OPTIONS=origin_history_size=7 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK7 < %t.out
+
+// RUN: MSAN_OPTIONS=origin_history_size=2 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK2 < %t.out
+
+// RUN: MSAN_OPTIONS=origin_history_per_stack_limit=1 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK-PER-STACK < %t.out
+
+// RUN: MSAN_OPTIONS=origin_history_size=7,origin_history_per_stack_limit=0 not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK7 < %t.out
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static char *buf, *cur, *end;
+void init() {
+ buf = new char[1000];
+#ifdef STACK
+ char stackbuf[1000];
+ char *volatile p = stackbuf;
+ memcpy(buf, p, 1000);
+#endif
+ cur = buf;
+ end = buf + 1000;
+}
+
+void line_flush() {
+ char *p;
+ for (p = cur - 1; p >= buf; --p)
+ if (*p == '\n')
+ break;
+ if (p >= buf) {
+ size_t write_sz = p - buf + 1;
+ // write(2, buf, write_sz);
+ memmove(buf, p + 1, end - p - 1);
+ cur -= write_sz;
+ }
+}
+
+void buffered_write(const char *p, size_t sz) {
+ while (sz > 0) {
+ size_t copy_sz = end - cur;
+ if (sz < copy_sz) copy_sz = sz;
+ memcpy(cur, p, copy_sz);
+ cur += copy_sz;
+ sz -= copy_sz;
+ line_flush();
+ }
+}
+
+void fn1() {
+ buffered_write("a\n", 2);
+}
+
+void fn2() {
+ buffered_write("a\n", 2);
+}
+
+void fn3() {
+ buffered_write("a\n", 2);
+}
+
+int main(void) {
+ init();
+ for (int i = 0; i < 2000; ++i) {
+ fn1();
+ fn2();
+ fn3();
+ }
+ return buf[50];
+}
+
+// CHECK7: WARNING: MemorySanitizer: use-of-uninitialized-value
+// CHECK7-NOT: Uninitialized value was stored to memory at
+// CHECK7: Uninitialized value was stored to memory at
+// CHECK7-NOT: Uninitialized value was stored to memory at
+// CHECK7: Uninitialized value was stored to memory at
+// CHECK7-NOT: Uninitialized value was stored to memory at
+// CHECK7: Uninitialized value was stored to memory at
+// CHECK7-NOT: Uninitialized value was stored to memory at
+// CHECK7: Uninitialized value was stored to memory at
+// CHECK7-NOT: Uninitialized value was stored to memory at
+// CHECK7: Uninitialized value was stored to memory at
+// CHECK7-NOT: Uninitialized value was stored to memory at
+// CHECK7: Uninitialized value was stored to memory at
+// CHECK7-NOT: Uninitialized value was stored to memory at
+// CHECK7: Uninitialized value was created
+
+// CHECK2: WARNING: MemorySanitizer: use-of-uninitialized-value
+// CHECK2-NOT: Uninitialized value was stored to memory at
+// CHECK2: Uninitialized value was stored to memory at
+// CHECK2-NOT: Uninitialized value was stored to memory at
+// CHECK2: Uninitialized value was created
+
+// CHECK-PER-STACK: WARNING: MemorySanitizer: use-of-uninitialized-value
+// CHECK-PER-STACK: Uninitialized value was stored to memory at
+// CHECK-PER-STACK: in fn3
+// CHECK-PER-STACK: Uninitialized value was stored to memory at
+// CHECK-PER-STACK: in fn2
+// CHECK-PER-STACK: Uninitialized value was stored to memory at
+// CHECK-PER-STACK: in fn1
+// CHECK-PER-STACK: Uninitialized value was created
+
+// CHECK-UNLIMITED: WARNING: MemorySanitizer: use-of-uninitialized-value
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was stored to memory at
+// CHECK-UNLIMITED: Uninitialized value was created
diff --git a/test/msan/chained_origin_memcpy.cc b/test/msan/chained_origin_memcpy.cc
new file mode 100644
index 000000000000..f4c2f7fcac87
--- /dev/null
+++ b/test/msan/chained_origin_memcpy.cc
@@ -0,0 +1,61 @@
+// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -DOFFSET=0 -O3 %s -o %t && \
+// RUN: not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-Z1 < %t.out
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -DOFFSET=10 -m64 -O3 %s -o %t && \
+// RUN: not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-Z2 < %t.out
+
+
+// RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -m64 -DOFFSET=0 -O3 %s -o %t && \
+// RUN: not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-Z1 < %t.out
+
+// RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -DOFFSET=10 -m64 -O3 %s -o %t && \
+// RUN: not %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-Z2 < %t.out
+
+
+#include <stdio.h>
+#include <string.h>
+
+int xx[10000];
+int yy[10000];
+volatile int idx = 30;
+
+__attribute__((noinline))
+void fn_g(int a, int b) {
+ xx[idx] = a; xx[idx + 10] = b;
+}
+
+__attribute__((noinline))
+void fn_f(int a, int b) {
+ fn_g(a, b);
+}
+
+__attribute__((noinline))
+void fn_h() {
+ memcpy(&yy, &xx, sizeof(xx));
+}
+
+int main(int argc, char *argv[]) {
+ int volatile z1;
+ int volatile z2;
+ fn_f(z1, z2);
+ fn_h();
+ return yy[idx + OFFSET];
+}
+
+// CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+// CHECK: {{#0 .* in main .*chained_origin_memcpy.cc:46}}
+
+// CHECK: Uninitialized value was stored to memory at
+// CHECK: {{#1 .* in fn_h.*chained_origin_memcpy.cc:38}}
+
+// CHECK: Uninitialized value was stored to memory at
+// CHECK: {{#0 .* in fn_g.*chained_origin_memcpy.cc:28}}
+// CHECK: {{#1 .* in fn_f.*chained_origin_memcpy.cc:33}}
+
+// CHECK-Z1: Uninitialized value was created by an allocation of 'z1' in the stack frame of function 'main'
+// CHECK-Z2: Uninitialized value was created by an allocation of 'z2' in the stack frame of function 'main'
+// CHECK: {{#0 .* in main.*chained_origin_memcpy.cc:41}}
diff --git a/test/msan/chained_origin_with_signals.cc b/test/msan/chained_origin_with_signals.cc
new file mode 100644
index 000000000000..2841e34a1f1d
--- /dev/null
+++ b/test/msan/chained_origin_with_signals.cc
@@ -0,0 +1,36 @@
+// Check that stores in signal handlers are not recorded in origin history.
+// This is, in fact, undesired behavior caused by our chained origins
+// implementation being not async-signal-safe.
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t && \
+// RUN: not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+// RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -m64 -O3 %s -o %t && \
+// RUN: not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+#include <signal.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+volatile int x, y;
+
+void SignalHandler(int signo) {
+ y = x;
+}
+
+int main(int argc, char *argv[]) {
+ int volatile z;
+ x = z;
+
+ signal(SIGHUP, SignalHandler);
+ kill(getpid(), SIGHUP);
+ signal(SIGHUP, SIG_DFL);
+
+ return y;
+}
+
+// CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+// CHECK-NOT: in SignalHandler
diff --git a/test/msan/check_mem_is_initialized.cc b/test/msan/check_mem_is_initialized.cc
new file mode 100644
index 000000000000..7d2328810d90
--- /dev/null
+++ b/test/msan/check_mem_is_initialized.cc
@@ -0,0 +1,33 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+
+#include <sanitizer/msan_interface.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv) {
+ int *volatile p = (int *)malloc(sizeof(int));
+
+ __msan_check_mem_is_initialized(p, sizeof(*p));
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: {{#0 0x.* in main .*check_mem_is_initialized.cc:}}[[@LINE-2]]
+
+ // CHECK-ORIGINS: Uninitialized value was created by a heap allocation
+ // CHECK-ORIGINS: {{#0 0x.* in .*malloc}}
+ // CHECK-ORIGINS: {{#1 0x.* in main .*check_mem_is_initialized.cc:}}[[@LINE-8]]
+ return 0;
+}
diff --git a/test/msan/coverage-levels.cc b/test/msan/coverage-levels.cc
new file mode 100644
index 000000000000..7c2e143d3ab8
--- /dev/null
+++ b/test/msan/coverage-levels.cc
@@ -0,0 +1,28 @@
+// Test various levels of coverage
+//
+// RUN: %clangxx_msan -DINIT_VAR=1 -O1 -fsanitize-coverage=1 %s -o %t
+// RUN: mkdir -p %T/coverage-levels
+// RUN: MSAN_OPTIONS=coverage=1:verbosity=1:coverage_dir=%T/coverage-levels %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 --check-prefix=CHECK_NOWARN
+// RUN: %clangxx_msan -O1 -fsanitize-coverage=1 %s -o %t
+// RUN: MSAN_OPTIONS=coverage=1:verbosity=1:coverage_dir=%T/coverage-levels not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 --check-prefix=CHECK_WARN
+// RUN: %clangxx_msan -O1 -fsanitize-coverage=2 %s -o %t
+// RUN: MSAN_OPTIONS=coverage=1:verbosity=1:coverage_dir=%T/coverage-levels not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 --check-prefix=CHECK_WARN
+// RUN: %clangxx_msan -O1 -fsanitize-coverage=3 %s -o %t
+// RUN: MSAN_OPTIONS=coverage=1:verbosity=1:coverage_dir=%T/coverage-levels not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3 --check-prefix=CHECK_WARN
+//
+volatile int sink;
+int main(int argc, char **argv) {
+ int var;
+#if INIT_VAR
+ var = 0;
+#endif
+ if (argc == 0)
+ sink = 0;
+ return *(volatile int*)&var;
+}
+
+// CHECK_WARN: WARNING: MemorySanitizer: use-of-uninitialized-value
+// CHECK_NOWARN-NOT: ERROR
+// CHECK1: 1 PCs written
+// CHECK2: 2 PCs written
+// CHECK3: 3 PCs written
diff --git a/test/msan/cxa_atexit.cc b/test/msan/cxa_atexit.cc
new file mode 100644
index 000000000000..0aa36ecee011
--- /dev/null
+++ b/test/msan/cxa_atexit.cc
@@ -0,0 +1,28 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p
+
+// PR17377: C++ module destructors get stale argument shadow.
+
+#include <stdio.h>
+#include <stdlib.h>
+class A {
+public:
+ // This destructor get stale argument shadow left from the call to f().
+ ~A() {
+ if (this)
+ exit(0);
+ }
+};
+
+A a;
+
+__attribute__((noinline))
+void f(long x) {
+}
+
+int main(void) {
+ long x;
+ long * volatile p = &x;
+ // This call poisons TLS shadow for the first function argument.
+ f(*p);
+ return 0;
+}
diff --git a/test/msan/death-callback.cc b/test/msan/death-callback.cc
new file mode 100644
index 000000000000..6d0488339998
--- /dev/null
+++ b/test/msan/death-callback.cc
@@ -0,0 +1,39 @@
+// RUN: %clangxx_msan -m64 -DERROR %s -o %t && not %run %t 2>&1 | \
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NOCB
+// RUN: %clangxx_msan -m64 -DERROR -DMSANCB_SET %s -o %t && not %run %t 2>&1 | \
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-CB
+// RUN: %clangxx_msan -m64 -DERROR -DMSANCB_SET -DMSANCB_CLEAR %s -o %t && not %run %t 2>&1 | \
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NOCB
+// RUN: %clangxx_msan -m64 -DMSANCB_SET %s -o %t && %run %t 2>&1 | \
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NOCB
+
+#include <sanitizer/msan_interface.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void cb(void) {
+ fprintf(stderr, "msan-death-callback\n");
+}
+
+int main(int argc, char **argv) {
+ int *volatile p = (int *)malloc(sizeof(int));
+ *p = 42;
+ free(p);
+
+#ifdef MSANCB_SET
+ __msan_set_death_callback(cb);
+#endif
+
+#ifdef MSANCB_CLEAR
+ __msan_set_death_callback(0);
+#endif
+
+#ifdef ERROR
+ if (*p)
+ exit(0);
+#endif
+ // CHECK-CB: msan-death-callback
+ // CHECK-NOCB-NOT: msan-death-callback
+ fprintf(stderr, "done\n");
+ return 0;
+}
diff --git a/test/msan/default_blacklist.cc b/test/msan/default_blacklist.cc
new file mode 100644
index 000000000000..32cc02257cb0
--- /dev/null
+++ b/test/msan/default_blacklist.cc
@@ -0,0 +1,3 @@
+// Test that MSan uses the default blacklist from resource directory.
+// RUN: %clangxx_msan -### %s 2>&1 | FileCheck %s
+// CHECK: fsanitize-blacklist={{.*}}msan_blacklist.txt
diff --git a/test/msan/dlerror.cc b/test/msan/dlerror.cc
new file mode 100644
index 000000000000..2c726d36041e
--- /dev/null
+++ b/test/msan/dlerror.cc
@@ -0,0 +1,14 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <string.h>
+
+int main(void) {
+ void *p = dlopen("/bad/file/name", RTLD_NOW);
+ assert(!p);
+ char *s = dlerror();
+ printf("%s, %zu\n", s, strlen(s));
+ return 0;
+}
diff --git a/test/msan/dso-origin.cc b/test/msan/dso-origin.cc
new file mode 100644
index 000000000000..ba008c00718d
--- /dev/null
+++ b/test/msan/dso-origin.cc
@@ -0,0 +1,48 @@
+// Build a library with origin tracking and an executable w/o origin tracking.
+// Test that origin tracking is enabled at runtime.
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -DBUILD_SO -fPIC -shared -o %t-so.so
+// RUN: %clangxx_msan -m64 -O0 %s %t-so.so -o %t && not %run %t 2>&1 | FileCheck %s
+
+#ifdef BUILD_SO
+
+#include <stdlib.h>
+
+extern "C" {
+void my_access(int *p) {
+ volatile int tmp;
+ // Force initialize-ness check.
+ if (*p)
+ tmp = 1;
+}
+
+void *my_alloc(unsigned sz) {
+ return malloc(sz);
+}
+} // extern "C"
+
+#else // BUILD_SO
+
+#include <stdlib.h>
+
+extern "C" {
+void my_access(int *p);
+void *my_alloc(unsigned sz);
+}
+
+int main(int argc, char **argv) {
+ int *x = (int *)my_alloc(sizeof(int));
+ my_access(x);
+ delete x;
+
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: {{#0 0x.* in my_access .*dso-origin.cc:}}
+ // CHECK: {{#1 0x.* in main .*dso-origin.cc:}}[[@LINE-5]]
+ // CHECK: Uninitialized value was created by a heap allocation
+ // CHECK: {{#0 0x.* in .*malloc}}
+ // CHECK: {{#1 0x.* in my_alloc .*dso-origin.cc:}}
+ // CHECK: {{#2 0x.* in main .*dso-origin.cc:}}[[@LINE-10]]
+ // CHECK: SUMMARY: MemorySanitizer: use-of-uninitialized-value {{.*dso-origin.cc:.* my_access}}
+ return 0;
+}
+
+#endif // BUILD_SO
diff --git a/test/msan/dtls_test.c b/test/msan/dtls_test.c
new file mode 100644
index 000000000000..cb88ede2f0a6
--- /dev/null
+++ b/test/msan/dtls_test.c
@@ -0,0 +1,60 @@
+/* RUN: %clang_msan -g -m64 %s -o %t
+ RUN: %clang_msan -g -m64 %s -DBUILD_SO -fPIC -o %t-so.so -shared
+ RUN: %run %t 2>&1
+
+ 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
+*/
+
+#ifndef BUILD_SO
+#include <assert.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+typedef long *(* get_t)();
+get_t GetTls;
+void *Thread1(void *unused) {
+ long uninitialized;
+ long *x = GetTls();
+ if (*x)
+ fprintf(stderr, "bar\n");
+ *x = uninitialized;
+ fprintf(stderr, "stack: %p dtls: %p\n", &x, x);
+ return 0;
+}
+
+void *Thread2(void *unused) {
+ long *x = GetTls();
+ fprintf(stderr, "stack: %p dtls: %p\n", &x, x);
+ if (*x)
+ fprintf(stderr, "foo\n"); // False negative here.
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+ char path[4096];
+ snprintf(path, sizeof(path), "%s-so.so", argv[0]);
+ int i;
+
+ 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);
+
+ pthread_t t;
+ pthread_create(&t, 0, Thread1, 0);
+ pthread_join(t, 0);
+ pthread_create(&t, 0, Thread2, 0);
+ pthread_join(t, 0);
+ return 0;
+}
+#else // BUILD_SO
+__thread long huge_thread_local_array[1 << 17];
+long *GetTls() {
+ return &huge_thread_local_array[0];
+}
+#endif
diff --git a/test/msan/errno.cc b/test/msan/errno.cc
new file mode 100644
index 000000000000..8af8eb5ee6f9
--- /dev/null
+++ b/test/msan/errno.cc
@@ -0,0 +1,17 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int main()
+{
+ int x;
+ int *volatile p = &x;
+ errno = *p;
+ int res = read(-1, 0, 0);
+ assert(res == -1);
+ if (errno) printf("errno %d\n", errno);
+ return 0;
+}
diff --git a/test/msan/fork.cc b/test/msan/fork.cc
new file mode 100644
index 000000000000..10de8a9379d8
--- /dev/null
+++ b/test/msan/fork.cc
@@ -0,0 +1,121 @@
+// Test that chained origins are fork-safe.
+// Run a number of threads that create new chained origins, then fork
+// and verify that origin reads do not deadlock in the child process.
+
+// RUN: %clangxx_msan -std=c++11 -fsanitize-memory-track-origins=2 -g -m64 -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
+
+// 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
+// a kernel bug:
+// https://lkml.org/lkml/2014/2/17/324
+
+
+#include <pthread.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <errno.h>
+
+#include <sanitizer/msan_interface.h>
+
+int done;
+
+void copy_uninit_thread2() {
+ volatile int x;
+ volatile int v;
+ while (true) {
+ v = x;
+ x = v;
+ if (__atomic_load_n(&done, __ATOMIC_RELAXED))
+ return;
+ }
+}
+
+void copy_uninit_thread1(int level) {
+ if (!level)
+ copy_uninit_thread2();
+ else
+ copy_uninit_thread1(level - 1);
+}
+
+void *copy_uninit_thread(void *id) {
+ copy_uninit_thread1((long)id);
+ return 0;
+}
+
+// Run through stackdepot in the child process.
+// If any of the hash table cells are locked, this may deadlock.
+void child() {
+ volatile int x;
+ volatile int v;
+ for (int i = 0; i < 10000; ++i) {
+ v = x;
+ x = v;
+ }
+ write(2, "done\n", 5);
+}
+
+void test() {
+ const int kThreads = 10;
+ pthread_t t[kThreads];
+ for (int i = 0; i < kThreads; ++i)
+ pthread_create(&t[i], NULL, copy_uninit_thread, (void*)(long)i);
+ usleep(100000);
+ pid_t pid = fork();
+ if (pid) {
+ // parent
+ __atomic_store_n(&done, 1, __ATOMIC_RELAXED);
+ pid_t p;
+ while ((p = wait(NULL)) == -1) { }
+ } else {
+ // child
+ child();
+ }
+}
+
+int main() {
+ const int kChildren = 20;
+ for (int i = 0; i < kChildren; ++i) {
+ pid_t pid = fork();
+ if (pid) {
+ // parent
+ } else {
+ test();
+ exit(0);
+ }
+ }
+
+ for (int i = 0; i < kChildren; ++i) {
+ pid_t p;
+ while ((p = wait(NULL)) == -1) { }
+ }
+
+ return 0;
+}
+
+// Expect 20 (== kChildren) "done" messages.
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
+// CHECK: done
diff --git a/test/msan/ftime.cc b/test/msan/ftime.cc
new file mode 100644
index 000000000000..2d0935d18037
--- /dev/null
+++ b/test/msan/ftime.cc
@@ -0,0 +1,14 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t
+
+#include <assert.h>
+#include <sys/timeb.h>
+
+#include <sanitizer/msan_interface.h>
+
+int main(void) {
+ struct timeb tb;
+ int res = ftime(&tb);
+ assert(!res);
+ assert(__msan_test_shadow(&tb, sizeof(tb)) == -1);
+ return 0;
+}
diff --git a/test/msan/getaddrinfo-positive.cc b/test/msan/getaddrinfo-positive.cc
new file mode 100644
index 000000000000..7658cd504dba
--- /dev/null
+++ b/test/msan/getaddrinfo-positive.cc
@@ -0,0 +1,23 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <stdlib.h>
+
+volatile int z;
+
+int main(void) {
+ struct addrinfo *ai;
+ struct addrinfo hint;
+ int res = getaddrinfo("localhost", NULL, NULL, &ai);
+ if (ai) z = 1; // OK
+ res = getaddrinfo("localhost", NULL, &hint, &ai);
+ // CHECK: Uninitialized bytes in __interceptor_getaddrinfo at offset 0 inside [0x{{.*}}, 48)
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: #0 {{.*}} in main {{.*}}getaddrinfo-positive.cc:[[@LINE-3]]
+ return 0;
+}
diff --git a/test/msan/getaddrinfo.cc b/test/msan/getaddrinfo.cc
new file mode 100644
index 000000000000..abab8bd78f75
--- /dev/null
+++ b/test/msan/getaddrinfo.cc
@@ -0,0 +1,24 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <stdlib.h>
+
+void poison_stack_ahead() {
+ char buf[100000];
+ // With -O0 this poisons a large chunk of stack.
+}
+
+int main(void) {
+ poison_stack_ahead();
+
+ struct addrinfo *ai;
+
+ // This should trigger loading of libnss_dns and friends.
+ // Those libraries are typically uninstrumented.They will call strlen() on a
+ // stack-allocated buffer, which is very likely to be poisoned. Test that we
+ // don't report this as an UMR.
+ int res = getaddrinfo("not-in-etc-hosts", NULL, NULL, &ai);
+ return 0;
+}
diff --git a/test/msan/getc_unlocked.c b/test/msan/getc_unlocked.c
new file mode 100644
index 000000000000..7df958ad657a
--- /dev/null
+++ b/test/msan/getc_unlocked.c
@@ -0,0 +1,32 @@
+// RUN: %clangxx_msan -DGETC -m64 -O0 -g -xc++ %s -o %t && %run %t
+// RUN: %clangxx_msan -DGETC -m64 -O3 -g -xc++ %s -o %t && %run %t
+// RUN: %clang_msan -DGETC -m64 -O0 -g %s -o %t && %run %t
+// RUN: %clang_msan -DGETC -m64 -O3 -g %s -o %t && %run %t
+
+// RUN: %clangxx_msan -DGETCHAR -m64 -O0 -g -xc++ %s -o %t && %run %t
+// RUN: %clangxx_msan -DGETCHAR -m64 -O3 -g -xc++ %s -o %t && %run %t
+// RUN: %clang_msan -DGETCHAR -m64 -O0 -g %s -o %t && %run %t
+// RUN: %clang_msan -DGETCHAR -m64 -O3 -g %s -o %t && %run %t
+
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int main() {
+ FILE *stream = fopen("/dev/zero", "r");
+ flockfile (stream);
+ int c;
+#if defined(GETCHAR)
+ int res = dup2(fileno(stream), 0);
+ assert(res == 0);
+ c = getchar_unlocked();
+#elif defined(GETC)
+ c = getc_unlocked (stream);
+#endif
+ funlockfile (stream);
+ if (c == EOF)
+ return 1;
+ printf("%c\n", (char)c);
+ fclose(stream);
+ return 0;
+}
diff --git a/test/msan/getline.cc b/test/msan/getline.cc
new file mode 100644
index 000000000000..51e105e0be5c
--- /dev/null
+++ b/test/msan/getline.cc
@@ -0,0 +1,36 @@
+// RUN: echo "abcde" > %t-testdata
+// RUN: echo "12345" >> %t-testdata
+// RUN: %clangxx_msan -O0 %s -o %t && %run %t %t-testdata
+// RUN: %clangxx_msan -O2 %s -o %t && %run %t %t-testdata
+// RUN: %clang_msan -O0 -xc %s -o %t && %run %t %t-testdata
+// RUN: %clang_msan -O2 -xc %s -o %t && %run %t %t-testdata
+// RUN: %clang_msan -O0 -xc -D_GNU_SOURCE=1 %s -o %t && %run %t %t-testdata
+// RUN: %clang_msan -O2 -xc -D_GNU_SOURCE=1 %s -o %t && %run %t %t-testdata
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char **argv) {
+ assert(argc == 2);
+ printf("%s\n", argv[1]);
+
+ FILE *fp = fopen(argv[1], "r");
+ assert(fp);
+
+ char *line = 0;
+ size_t len = 0;
+ int n = getline(&line, &len, fp);
+ assert(n == 6);
+ assert(strcmp(line, "abcde\n") == 0);
+
+ n = getline(&line, &len, fp);
+ assert(n == 6);
+ assert(strcmp(line, "12345\n") == 0);
+
+ free(line);
+ fclose(fp);
+
+ return 0;
+}
diff --git a/test/msan/heap-origin.cc b/test/msan/heap-origin.cc
new file mode 100644
index 000000000000..0920001beed7
--- /dev/null
+++ b/test/msan/heap-origin.cc
@@ -0,0 +1,31 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+
+#include <stdlib.h>
+int main(int argc, char **argv) {
+ char *volatile x = (char*)malloc(5 * sizeof(char));
+ return *x;
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: {{#0 0x.* in main .*heap-origin.cc:}}[[@LINE-2]]
+
+ // CHECK-ORIGINS: Uninitialized value was created by a heap allocation
+ // CHECK-ORIGINS: {{#0 0x.* in .*malloc}}
+ // CHECK-ORIGINS: {{#1 0x.* in main .*heap-origin.cc:}}[[@LINE-7]]
+
+ // CHECK: SUMMARY: MemorySanitizer: use-of-uninitialized-value {{.*heap-origin.cc:.* main}}
+}
diff --git a/test/msan/iconv.cc b/test/msan/iconv.cc
new file mode 100644
index 000000000000..ea6958b79b96
--- /dev/null
+++ b/test/msan/iconv.cc
@@ -0,0 +1,48 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O0 -g -DPOSITIVE %s -o %t && not %run %t |& FileCheck %s
+
+#include <assert.h>
+#include <iconv.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+int main(void) {
+ iconv_t cd = iconv_open("ASCII", "ASCII");
+ assert(cd != (iconv_t)-1);
+
+ char inbuf_[100];
+ strcpy(inbuf_, "sample text");
+ char outbuf_[100];
+ char *inbuf = inbuf_;
+ char *outbuf = outbuf_;
+ size_t inbytesleft = strlen(inbuf_);
+ size_t outbytesleft = sizeof(outbuf_);
+
+#ifdef POSITIVE
+ {
+ char u;
+ char *volatile p = &u;
+ inbuf_[5] = *p;
+ }
+#endif
+
+ size_t res;
+ res = iconv(cd, 0, 0, 0, 0);
+ assert(res != (size_t)-1);
+
+ res = iconv(cd, 0, 0, &outbuf, &outbytesleft);
+ assert(res != (size_t)-1);
+
+ res = iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
+ // CHECK: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: #0 {{.*}} in main {{.*}}iconv.cc:[[@LINE-2]]
+ assert(res != (size_t)-1);
+ assert(inbytesleft == 0);
+
+ assert(memcmp(inbuf_, outbuf_, strlen(inbuf_)) == 0);
+
+ iconv_close(cd);
+ return 0;
+}
diff --git a/test/msan/if_indextoname.cc b/test/msan/if_indextoname.cc
new file mode 100644
index 000000000000..b74aec16c98a
--- /dev/null
+++ b/test/msan/if_indextoname.cc
@@ -0,0 +1,23 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t 2>&1
+// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t 2>&1
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t 2>&1
+
+#include <assert.h>
+#include <errno.h>
+#include <net/if.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <sanitizer/msan_interface.h>
+
+int main(int argc, char *argv[]) {
+ char ifname[IF_NAMESIZE + 1];
+ assert(0 == __msan_test_shadow(ifname, sizeof(ifname)));
+ if (!if_indextoname(1, ifname)) {
+ assert(errno == ENXIO);
+ printf("No network interfaces found.\n");
+ return 0;
+ }
+ assert(strlen(ifname) + 1 == __msan_test_shadow(ifname, sizeof(ifname)));
+ return 0;
+}
diff --git a/test/msan/ifaddrs.cc b/test/msan/ifaddrs.cc
new file mode 100644
index 000000000000..6a0db3a5b71f
--- /dev/null
+++ b/test/msan/ifaddrs.cc
@@ -0,0 +1,50 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p 2>&1
+// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p 2>&1
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p 2>&1
+
+#include <assert.h>
+#include <errno.h>
+#include <ifaddrs.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <vector>
+
+#include <sanitizer/msan_interface.h>
+
+#define CHECK_AND_PUSH(addr, size) \
+ if (addr) { \
+ assert(-1 == __msan_test_shadow(addr, sizeof(size))); \
+ ranges.push_back(std::make_pair((void *)addr, (size_t)size)); \
+ }
+
+int main(int argc, char *argv[]) {
+ struct ifaddrs *ifas;
+
+ assert(0 == __msan_test_shadow(&ifas, sizeof(ifaddrs *)));
+ int res = getifaddrs(&ifas);
+ if (res == -1) {
+ assert(errno == ENOSYS);
+ printf("getifaddrs() is not implemented\n");
+ return 0;
+ }
+ assert(res == 0);
+ assert(-1 == __msan_test_shadow(&ifas, sizeof(ifaddrs *)));
+
+ std::vector<std::pair<void *, size_t> > ranges;
+ ifaddrs *p = ifas;
+ while (p) {
+ CHECK_AND_PUSH(p, sizeof(ifaddrs));
+ CHECK_AND_PUSH(p->ifa_name, strlen(p->ifa_name) + 1);
+ CHECK_AND_PUSH(p->ifa_addr, sizeof(*p->ifa_addr));
+ CHECK_AND_PUSH(p->ifa_netmask, sizeof(*p->ifa_netmask));
+ CHECK_AND_PUSH(p->ifa_broadaddr, sizeof(*p->ifa_broadaddr));
+ CHECK_AND_PUSH(p->ifa_dstaddr, sizeof(*p->ifa_dstaddr));
+ p = p->ifa_next;
+ }
+
+ freeifaddrs(ifas);
+ for (int i = 0; i < ranges.size(); i++)
+ assert(0 == __msan_test_shadow(ranges[i].first, ranges[i].second));
+ return 0;
+}
diff --git a/test/msan/initgroups.cc b/test/msan/initgroups.cc
new file mode 100644
index 000000000000..94f6cd8252f3
--- /dev/null
+++ b/test/msan/initgroups.cc
@@ -0,0 +1,11 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t
+
+#include <sys/types.h>
+#include <grp.h>
+
+int main(void) {
+ initgroups("root", 0);
+ // The above fails unless you are root. Does not matter, MSan false positive
+ // (which we are testing for) happens anyway.
+ return 0;
+}
diff --git a/test/msan/inline.cc b/test/msan/inline.cc
new file mode 100644
index 000000000000..b2fa96150856
--- /dev/null
+++ b/test/msan/inline.cc
@@ -0,0 +1,20 @@
+// RUN: %clangxx_msan -O3 %s -o %t && %run %t
+
+// Test that no_sanitize_memory attribute applies even when the function would
+// be normally inlined.
+
+#include <stdlib.h>
+
+__attribute__((no_sanitize_memory))
+int f(int *p) {
+ if (*p) // BOOOM?? Nope!
+ exit(0);
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ int x;
+ int * volatile p = &x;
+ int res = f(p);
+ return 0;
+}
diff --git a/test/msan/insertvalue_origin.cc b/test/msan/insertvalue_origin.cc
new file mode 100644
index 000000000000..545debffaad5
--- /dev/null
+++ b/test/msan/insertvalue_origin.cc
@@ -0,0 +1,35 @@
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s < %t.out
+
+// Test origin propagation through insertvalue IR instruction.
+
+#include <stdio.h>
+#include <stdint.h>
+
+struct mypair {
+ int64_t x;
+ int y;
+};
+
+mypair my_make_pair(int64_t x, int y) {
+ mypair p;
+ p.x = x;
+ p.y = y;
+ return p;
+}
+
+int main() {
+ int64_t * volatile p = new int64_t;
+ mypair z = my_make_pair(*p, 0);
+ if (z.x)
+ printf("zzz\n");
+ // CHECK: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: {{in main .*insertvalue_origin.cc:}}[[@LINE-3]]
+
+ // CHECK: Uninitialized value was created by a heap allocation
+ // CHECK: {{in main .*insertvalue_origin.cc:}}[[@LINE-8]]
+ delete p;
+ return 0;
+}
diff --git a/test/msan/ioctl.cc b/test/msan/ioctl.cc
new file mode 100644
index 000000000000..caa5c274f5eb
--- /dev/null
+++ b/test/msan/ioctl.cc
@@ -0,0 +1,20 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O3 -g %s -o %t && %run %t
+
+#include <assert.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+int main(int argc, char **argv) {
+ int fd = socket(AF_INET, SOCK_DGRAM, 0);
+
+ unsigned int z;
+ int res = ioctl(fd, FIOGETOWN, &z);
+ assert(res == 0);
+ close(fd);
+ if (z)
+ exit(0);
+ return 0;
+}
diff --git a/test/msan/ioctl_custom.cc b/test/msan/ioctl_custom.cc
new file mode 100644
index 000000000000..7c7fde4bd5d0
--- /dev/null
+++ b/test/msan/ioctl_custom.cc
@@ -0,0 +1,33 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O3 -g %s -o %t && %run %t
+
+// RUN: %clangxx_msan -DPOSITIVE -m64 -O0 -g %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_msan -DPOSITIVE -m64 -O3 -g %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <stdlib.h>
+#include <net/if.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+int main(int argc, char **argv) {
+ int fd = socket(AF_INET, SOCK_STREAM, 0);
+
+ struct ifreq ifreqs[20];
+ struct ifconf ifc;
+ ifc.ifc_ifcu.ifcu_req = ifreqs;
+#ifndef POSITIVE
+ ifc.ifc_len = sizeof(ifreqs);
+#endif
+ int res = ioctl(fd, SIOCGIFCONF, (void *)&ifc);
+ // CHECK: Uninitialized bytes in ioctl{{.*}} at offset 0 inside [0x{{.*}}, 4)
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: #{{.*}} in main {{.*}}ioctl_custom.cc:[[@LINE-3]]
+ assert(res == 0);
+ for (int i = 0; i < ifc.ifc_len / sizeof(*ifc.ifc_ifcu.ifcu_req); ++i)
+ printf("%d %zu %s\n", i, strlen(ifreqs[i].ifr_name), ifreqs[i].ifr_name);
+ return 0;
+}
diff --git a/test/msan/ioctl_sound.cc b/test/msan/ioctl_sound.cc
new file mode 100644
index 000000000000..ed896f761181
--- /dev/null
+++ b/test/msan/ioctl_sound.cc
@@ -0,0 +1,29 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O3 -g %s -o %t && %run %t
+
+#include <assert.h>
+#include <fcntl.h>
+#include <sound/asound.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <sanitizer/msan_interface.h>
+
+int main(int argc, char **argv) {
+ int fd = open("/dev/snd/controlC0", O_RDONLY);
+ if (fd < 0) {
+ printf("Unable to open sound device.");
+ return 0;
+ }
+ const unsigned sz = sizeof(snd_ctl_card_info);
+ void *info = malloc(sz + 1);
+ assert(__msan_test_shadow(info, sz) == 0);
+ assert(ioctl(fd, SNDRV_CTL_IOCTL_CARD_INFO, info) >= 0);
+ assert(__msan_test_shadow(info, sz + 1) == sz);
+ close(fd);
+ free(info);
+ return 0;
+}
diff --git a/test/msan/keep-going-dso.cc b/test/msan/keep-going-dso.cc
new file mode 100644
index 000000000000..7975306c557f
--- /dev/null
+++ b/test/msan/keep-going-dso.cc
@@ -0,0 +1,33 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %run %t >%t.out 2>&1
+// FileCheck %s <%t.out
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %run %t >%t.out 2>&1
+// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out
+
+// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out
+// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %run %t >%t.out 2>&1
+// FileCheck %s <%t.out
+// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %run %t >%t.out 2>&1
+// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out
+
+// Test how -mllvm -msan-keep-going and MSAN_OPTIONS=keep_going affect reports
+// from interceptors.
+// -mllvm -msan-keep-going provides the default value of keep_going flag, but is
+// always overwritten by MSAN_OPTIONS
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char **argv) {
+ char *volatile x = (char*)malloc(5 * sizeof(char));
+ x[4] = 0;
+ if (strlen(x) < 3)
+ exit(0);
+ fprintf(stderr, "Done\n");
+ // CHECK-NOT: Done
+ // CHECK-KEEP-GOING: Done
+ return 0;
+}
diff --git a/test/msan/keep-going.cc b/test/msan/keep-going.cc
new file mode 100644
index 000000000000..6426574a9e50
--- /dev/null
+++ b/test/msan/keep-going.cc
@@ -0,0 +1,34 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// FileCheck %s <%t.out
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %run %t >%t.out 2>&1
+// FileCheck %s <%t.out
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %run %t >%t.out 2>&1
+// FileCheck %s <%t.out
+
+// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out
+// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %run %t >%t.out 2>&1
+// FileCheck %s <%t.out
+// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %run %t >%t.out 2>&1
+// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out
+// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=halt_on_error=1 not %run %t >%t.out 2>&1
+// FileCheck %s <%t.out
+// RUN: %clangxx_msan -m64 -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=halt_on_error=0 not %run %t >%t.out 2>&1
+// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out
+
+// Test behaviour of -mllvm -msan-keep-going and MSAN_OPTIONS=keep_going.
+// -mllvm -msan-keep-going provides the default value of keep_going flag; value
+// of 1 can be overwritten by MSAN_OPTIONS, value of 0 can not.
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv) {
+ char *volatile x = (char*)malloc(5 * sizeof(char));
+ if (x[0])
+ exit(0);
+ fprintf(stderr, "Done\n");
+ // CHECK-NOT: Done
+ // CHECK-KEEP-GOING: Done
+ return 0;
+}
diff --git a/test/msan/lit.cfg b/test/msan/lit.cfg
new file mode 100644
index 000000000000..f425e25957ac
--- /dev/null
+++ b/test/msan/lit.cfg
@@ -0,0 +1,30 @@
+# -*- Python -*-
+
+import os
+
+# Setup config name.
+config.name = 'MemorySanitizer'
+
+# 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_cxxflags = config.cxx_mode_flags + clang_msan_cflags
+
+def build_invocation(compile_flags):
+ return " " + " ".join([config.clang] + compile_flags) + " "
+
+config.substitutions.append( ("%clang_msan ", build_invocation(clang_msan_cflags)) )
+config.substitutions.append( ("%clangxx_msan ", build_invocation(clang_msan_cxxflags)) )
+
+# Default test suffixes.
+config.suffixes = ['.c', '.cc', '.cpp']
+
+# MemorySanitizer tests are currently supported on Linux only.
+if config.host_os not in ['Linux']:
+ config.unsupported = True
diff --git a/test/msan/lit.site.cfg.in b/test/msan/lit.site.cfg.in
new file mode 100644
index 000000000000..fb22a57a9e66
--- /dev/null
+++ b/test/msan/lit.site.cfg.in
@@ -0,0 +1,5 @@
+# Load common config for all compiler-rt lit tests.
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")
+
+# Load tool-specific config that would do the real work.
+lit_config.load_config(config, "@MSAN_LIT_SOURCE_DIR@/lit.cfg")
diff --git a/test/msan/mallinfo.cc b/test/msan/mallinfo.cc
new file mode 100644
index 000000000000..3f308683077e
--- /dev/null
+++ b/test/msan/mallinfo.cc
@@ -0,0 +1,12 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t
+
+#include <assert.h>
+#include <malloc.h>
+
+#include <sanitizer/msan_interface.h>
+
+int main(void) {
+ struct mallinfo mi = mallinfo();
+ assert(__msan_test_shadow(&mi, sizeof(mi)) == -1);
+ return 0;
+}
diff --git a/test/msan/mktime.cc b/test/msan/mktime.cc
new file mode 100644
index 000000000000..c419057c3907
--- /dev/null
+++ b/test/msan/mktime.cc
@@ -0,0 +1,26 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O0 -g -DUNINIT %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <time.h>
+
+#include <sanitizer/msan_interface.h>
+
+int main(void) {
+ struct tm tm;
+ tm.tm_year = 2014;
+ tm.tm_mon = 3;
+ tm.tm_mday = 28;
+#ifndef UNINIT
+ tm.tm_hour = 13;
+#endif
+ tm.tm_min = 4;
+ tm.tm_sec = 42;
+ tm.tm_isdst = -1;
+ time_t t = mktime(&tm);
+ // CHECK: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: in main{{.*}}mktime.cc:[[@LINE-2]]
+ assert(t != -1);
+ assert(__msan_test_shadow(&tm, sizeof(tm)) == -1);
+ return 0;
+}
diff --git a/test/msan/mmap_below_shadow.cc b/test/msan/mmap_below_shadow.cc
new file mode 100644
index 000000000000..4b5890ba0fb8
--- /dev/null
+++ b/test/msan/mmap_below_shadow.cc
@@ -0,0 +1,28 @@
+// Test mmap behavior when map address is below shadow range.
+// With MAP_FIXED, we return EINVAL.
+// Without MAP_FIXED, we ignore the address hint and map somewhere in
+// application range.
+
+// RUN: %clangxx_msan -m64 -O0 -DFIXED=0 %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O0 -DFIXED=1 %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O0 -DFIXED=0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O0 -DFIXED=1 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+#include <sys/mman.h>
+
+int main(void) {
+ // Hint address just below shadow.
+ uintptr_t hint = 0x4f0000000000ULL;
+ const uintptr_t app_start = 0x600000000000ULL;
+ uintptr_t p = (uintptr_t)mmap(
+ (void *)hint, 4096, PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS | (FIXED ? MAP_FIXED : 0), -1, 0);
+ if (FIXED)
+ assert(p == (uintptr_t)-1 && errno == EINVAL);
+ else
+ assert(p >= app_start);
+ return 0;
+}
diff --git a/test/msan/msan_check_mem_is_initialized.cc b/test/msan/msan_check_mem_is_initialized.cc
new file mode 100644
index 000000000000..33558cd2feb2
--- /dev/null
+++ b/test/msan/msan_check_mem_is_initialized.cc
@@ -0,0 +1,28 @@
+// RUN: %clangxx_msan -m64 -O0 -g -DPOSITIVE %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK
+// RUN: MSAN_OPTIONS=verbosity=1 not %run %t 2>&1 | \
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-VERBOSE
+
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t
+
+#include <sanitizer/msan_interface.h>
+
+int main(void) {
+ char p[32] = {};
+ __msan_poison(p + 10, 2);
+
+ __msan_check_mem_is_initialized(p, 10);
+ __msan_check_mem_is_initialized(p + 12, 30);
+#ifdef POSITIVE
+ __msan_check_mem_is_initialized(p + 5, 20);
+ // CHECK: Uninitialized bytes in __msan_check_mem_is_initialized at offset 5 inside [0x{{.*}}, 20)
+ // CHECK-VERBOSE: Shadow map of [0x{{.*}}, 0x{{.*}}), 20 bytes:
+ // CHECK-VERBOSE: 0x{{.*}}: ..000000 0000ffff 00000000 00000000
+ // CHECK-VERBOSE: 0x{{.*}}: 00000000 00...... ........ ........
+
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: #0 0x{{.*}}in main{{.*}}msan_check_mem_is_initialized.cc:[[@LINE-7]]
+#endif
+ return 0;
+}
+
diff --git a/test/msan/msan_dump_shadow.cc b/test/msan/msan_dump_shadow.cc
new file mode 100644
index 000000000000..08371e306f32
--- /dev/null
+++ b/test/msan/msan_dump_shadow.cc
@@ -0,0 +1,22 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+#include <sanitizer/msan_interface.h>
+
+int main(void) {
+ char *p = new char[16];
+ __msan_dump_shadow(p, 5);
+ delete[] p;
+ const char *q = "abc";
+ __msan_dump_shadow(q, 3);
+ return 0;
+}
+
+// CHECK: ff ff ff ff ff
+// CHECK: 00 00 00
diff --git a/test/msan/msan_print_shadow.cc b/test/msan/msan_print_shadow.cc
new file mode 100644
index 000000000000..0cc1d660be1b
--- /dev/null
+++ b/test/msan/msan_print_shadow.cc
@@ -0,0 +1,122 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-ORIGINS < %t.out
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ORIGINS < %t.out
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ORIGINS --check-prefix=CHECK-ORIGINS-2 < %t.out
+
+#include <sanitizer/msan_interface.h>
+
+int main(void) {
+ char volatile x;
+ char *p = new char[320];
+ p[2] = p[5] = 1;
+ p[8] = p[9] = p[10] = p[11] = p[12] = 2;
+
+ __msan_allocated_memory(p + 4*3, 4);
+ __msan_allocated_memory(p + 4*4, 4);
+ __msan_allocated_memory(p + 4*5, 4);
+ __msan_allocated_memory(p + 4*6, 4);
+ __msan_allocated_memory(p + 4*7, 4);
+ __msan_allocated_memory(p + 4*8, 4);
+ __msan_allocated_memory(p + 4*9, 4);
+ __msan_allocated_memory(p + 4*10, 4);
+ __msan_allocated_memory(p + 4*11, 4);
+ __msan_allocated_memory(p + 4*12, 4);
+ __msan_allocated_memory(p + 4*13, 4);
+ __msan_allocated_memory(p + 4*14, 4);
+ __msan_allocated_memory(p + 4*15, 4);
+ __msan_allocated_memory(p + 4*16, 4);
+ __msan_allocated_memory(p + 4*17, 4);
+ __msan_allocated_memory(p + 4*18, 4);
+ __msan_allocated_memory(p + 4*19, 4);
+ __msan_allocated_memory(p + 4*20, 4);
+ __msan_allocated_memory(p + 4*21, 4);
+ __msan_allocated_memory(p + 4*22, 4);
+ __msan_allocated_memory(p + 4*23, 4);
+ __msan_allocated_memory(p + 4*24, 4);
+ __msan_allocated_memory(p + 4*25, 4);
+ __msan_allocated_memory(p + 4*26, 4);
+ __msan_allocated_memory(p + 4*27, 4);
+ __msan_allocated_memory(p + 4*28, 4);
+ __msan_allocated_memory(p + 4*29, 4);
+ __msan_allocated_memory(p + 4*30, 4);
+ __msan_allocated_memory(p + 4*31, 4);
+
+ p[19] = x;
+
+ __msan_print_shadow(p+5, 297);
+ delete[] p;
+ return 0;
+}
+
+// CHECK: Shadow map of [{{.*}}), 297 bytes:
+
+// CHECK-NO-ORIGINS: 0x{{.*}}: ..00ffff 00000000 ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff
+// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffff.... ........
+
+// CHECK-ORIGINS: 0x{{.*}}: ..00ffff 00000000 ffffffff ffffffff |A . B C|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |D E F G|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |H I J K|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |L M N O|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |P Q R S|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |T U V W|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |X Y Z *|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |* * * A|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A|
+// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffff.... ........ |A A A .|
+
+// CHECK-ORIGINS: Origin A (origin_id {{.*}}):
+// CHECK-ORIGINS: Uninitialized value was created by a heap allocation
+// CHECK-ORIGINS: #1 {{.*}} in main{{.*}}msan_print_shadow.cc:14
+
+// CHECK-ORIGINS: Origin B (origin_id {{.*}}):
+// CHECK-ORIGINS: Uninitialized value was created by a heap allocation
+// CHECK-ORIGINS: #0 {{.*}} in __msan_allocated_memory
+// CHECK-ORIGINS: #1 {{.*}} in main{{.*}}msan_print_shadow.cc:18
+
+// CHECK-ORIGINS: Origin C (origin_id {{.*}}):
+// CHECK-ORIGINS-2: Uninitialized value was stored to memory at
+// CHECK-ORIGINS-2: #0 {{.*}} in main{{.*}}msan_print_shadow.cc:48
+// CHECK-ORIGINS: Uninitialized value was created by an allocation of 'x' in the stack frame of function 'main'
+// CHECK-ORIGINS: #0 {{.*}} in main{{.*}}msan_print_shadow.cc:12
+
+// CHECK-ORIGINS: Origin D (origin_id {{.*}}):
+// CHECK-ORIGINS: Uninitialized value was created by a heap allocation
+// CHECK-ORIGINS: #0 {{.*}} in __msan_allocated_memory
+// CHECK-ORIGINS: #1 {{.*}} in main{{.*}}msan_print_shadow.cc:20
+
+// ...
+
+// CHECK-ORIGINS: Origin Z (origin_id {{.*}}):
+// CHECK-ORIGINS: Uninitialized value was created by a heap allocation
+// CHECK-ORIGINS: #0 {{.*}} in __msan_allocated_memory
+// CHECK-ORIGINS: #1 {{.*}} in main{{.*}}msan_print_shadow.cc:42
diff --git a/test/msan/msan_print_shadow2.cc b/test/msan/msan_print_shadow2.cc
new file mode 100644
index 000000000000..343ee9e5c3de
--- /dev/null
+++ b/test/msan/msan_print_shadow2.cc
@@ -0,0 +1,49 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-ORIGINS < %t.out
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ORIGINS < %t.out
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ORIGINS < %t.out
+
+#include <sanitizer/msan_interface.h>
+
+int main(void) {
+ char *p = new char[16];
+ __msan_print_shadow(p, 1);
+ __msan_print_shadow(p+1, 1);
+ __msan_print_shadow(p+3, 1);
+ __msan_print_shadow(p+15, 1);
+ __msan_print_shadow(p, 0);
+ delete[] p;
+ int x = 0;
+ __msan_print_shadow(&x, 3);
+ return 0;
+}
+
+// CHECK: Shadow map of [0x{{.*}}, 0x{{.*}}), 1 bytes:
+// CHECK-NO-ORIGINS: 0x{{.*}}: ff...... ........ ........ ........
+// CHECK-ORIGINS: 0x{{.*}}: ff...... ........ ........ ........ |A . . .|
+// CHECK-ORIGINS: Origin A (origin_id {{.*}}):
+
+// CHECK: Shadow map of [0x{{.*}}, 0x{{.*}}), 1 bytes:
+// CHECK-NO-ORIGINS: 0x{{.*}}: ..ff.... ........ ........ ........
+// CHECK-ORIGINS: 0x{{.*}}: ..ff.... ........ ........ ........ |A . . .|
+// CHECK-ORIGINS: Origin A (origin_id {{.*}}):
+
+// CHECK: Shadow map of [0x{{.*}}, 0x{{.*}}), 1 bytes:
+// CHECK-NO-ORIGINS: 0x{{.*}}: ......ff ........ ........ ........
+// CHECK-ORIGINS: 0x{{.*}}: ......ff ........ ........ ........ |A . . .|
+// CHECK-ORIGINS: Origin A (origin_id {{.*}}):
+
+// CHECK: Shadow map of [0x{{.*}}, 0x{{.*}}), 1 bytes:
+// CHECK-NO-ORIGINS: 0x{{.*}}: ......ff ........ ........ ........
+// CHECK-ORIGINS: 0x{{.*}}: ......ff ........ ........ ........ |A . . .|
+// CHECK-ORIGINS: Origin A (origin_id {{.*}}):
+
+// CHECK: Shadow map of [0x{{.*}}, 0x{{.*}}), 0 bytes:
+
+// CHECK: Shadow map of [0x{{.*}}, 0x{{.*}}), 3 bytes:
+// CHECK-NO-ORIGINS: 0x{{.*}}: 000000.. ........ ........ ........
+// CHECK-ORIGINS: 0x{{.*}}: 000000.. ........ ........ ........ |. . . .|
diff --git a/test/msan/msan_print_shadow3.cc b/test/msan/msan_print_shadow3.cc
new file mode 100644
index 000000000000..c605ef18886d
--- /dev/null
+++ b/test/msan/msan_print_shadow3.cc
@@ -0,0 +1,16 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+#include <stdint.h>
+#include <sanitizer/msan_interface.h>
+
+int main(void) {
+ unsigned long long x = 0; // For 8-byte alignment.
+ uint32_t x_s = 0x12345678U;
+ __msan_partial_poison(&x, &x_s, sizeof(x_s));
+ __msan_print_shadow(&x, sizeof(x_s));
+ return 0;
+}
+
+// CHECK: Shadow map of [{{.*}}), 4 bytes:
+// CHECK: 0x{{.*}}: 87654321 ........ ........ ........
diff --git a/test/msan/mul_by_const.cc b/test/msan/mul_by_const.cc
new file mode 100644
index 000000000000..a975bb92167e
--- /dev/null
+++ b/test/msan/mul_by_const.cc
@@ -0,0 +1,27 @@
+// RUN: %clangxx_msan -m64 -O2 %s -o %t && %run %t
+
+#include <sanitizer/msan_interface.h>
+
+struct S {
+ S(int a0) : a(a0) {}
+ int a;
+ int b;
+};
+
+// Here S is passed to FooRun as a 64-bit integer.
+// This triggers an optimization where 10000 * s.a is transformed into
+// ((*(uint64_t *)&s) * (10000 * 2**32)) >> 32
+// Test that MSan understands that this kills the uninitialized high half of S
+// (i.e. S::b).
+void FooRun(S s) {
+ int64_t x = 10000 * s.a;
+ __msan_check_mem_is_initialized(&x, sizeof(x));
+}
+
+int main(void) {
+ S z(1);
+ // Take &z to ensure that it is built on stack.
+ S *volatile p = &z;
+ FooRun(z);
+ return 0;
+}
diff --git a/test/msan/no_sanitize_memory.cc b/test/msan/no_sanitize_memory.cc
new file mode 100644
index 000000000000..c5643816c281
--- /dev/null
+++ b/test/msan/no_sanitize_memory.cc
@@ -0,0 +1,34 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t >%t.out 2>&1
+// RUN: %clangxx_msan -m64 -O1 %s -o %t && %run %t >%t.out 2>&1
+// RUN: %clangxx_msan -m64 -O2 %s -o %t && %run %t >%t.out 2>&1
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t >%t.out 2>&1
+
+// RUN: %clangxx_msan -m64 -O0 %s -o %t -DCHECK_IN_F && %run %t >%t.out 2>&1
+// RUN: %clangxx_msan -m64 -O1 %s -o %t -DCHECK_IN_F && %run %t >%t.out 2>&1
+// RUN: %clangxx_msan -m64 -O2 %s -o %t -DCHECK_IN_F && %run %t >%t.out 2>&1
+// RUN: %clangxx_msan -m64 -O3 %s -o %t -DCHECK_IN_F && %run %t >%t.out 2>&1
+
+// Test that (no_sanitize_memory) functions
+// * don't check shadow values (-DCHECK_IN_F)
+// * treat all values loaded from memory as fully initialized (-UCHECK_IN_F)
+
+#include <stdlib.h>
+#include <stdio.h>
+
+__attribute__((noinline))
+__attribute__((no_sanitize_memory))
+int f(void) {
+ int x;
+ int * volatile p = &x;
+#ifdef CHECK_IN_F
+ if (*p)
+ exit(0);
+#endif
+ return *p;
+}
+
+int main(void) {
+ if (f())
+ exit(0);
+ return 0;
+}
diff --git a/test/msan/no_sanitize_memory_prop.cc b/test/msan/no_sanitize_memory_prop.cc
new file mode 100644
index 000000000000..4275ebbf78e1
--- /dev/null
+++ b/test/msan/no_sanitize_memory_prop.cc
@@ -0,0 +1,24 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t >%t.out 2>&1
+// RUN: %clangxx_msan -m64 -O1 %s -o %t && %run %t >%t.out 2>&1
+// RUN: %clangxx_msan -m64 -O2 %s -o %t && %run %t >%t.out 2>&1
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t >%t.out 2>&1
+
+// Test that (no_sanitize_memory) functions DO NOT propagate shadow.
+
+#include <stdlib.h>
+#include <stdio.h>
+
+__attribute__((noinline))
+__attribute__((no_sanitize_memory))
+int f(int x) {
+ return x;
+}
+
+int main(void) {
+ int x;
+ int * volatile p = &x;
+ int y = f(*p);
+ if (y)
+ exit(0);
+ return 0;
+}
diff --git a/test/msan/obstack.cc b/test/msan/obstack.cc
new file mode 100644
index 000000000000..222f43b839dc
--- /dev/null
+++ b/test/msan/obstack.cc
@@ -0,0 +1,37 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O0 -g -DPOSITIVE %s -o %t && not %run %t |& FileCheck %s
+
+#include <obstack.h>
+#include <sanitizer/msan_interface.h>
+#include <stdlib.h>
+
+static void *obstack_chunk_alloc(size_t sz) {
+ return malloc(sz);
+}
+
+static void obstack_chunk_free(void *p) {
+ free(p);
+}
+
+int main(void) {
+ obstack obs;
+ obstack_init(&obs);
+ for (size_t sz = 16; sz < 0xFFFF; sz *= 2) {
+ void *p = obstack_alloc(&obs, sz);
+ int data[10] = {0};
+ obstack_grow(&obs, &data, sizeof(data));
+ obstack_blank(&obs, sz);
+ obstack_grow(&obs, &data, sizeof(data));
+ obstack_int_grow(&obs, 13);
+ p = obstack_finish(&obs);
+#ifdef POSITIVE
+ if (sz == 4096) {
+ __msan_check_mem_is_initialized(p, sizeof(data));
+ __msan_check_mem_is_initialized(p, sizeof(data) + 1);
+ }
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: #0 0x{{.*}} in main{{.*}}obstack.cc:[[@LINE-30]]
+#endif
+ }
+ obstack_free(&obs, 0);
+}
diff --git a/test/msan/param_tls_limit.cc b/test/msan/param_tls_limit.cc
new file mode 100644
index 000000000000..869afc935773
--- /dev/null
+++ b/test/msan/param_tls_limit.cc
@@ -0,0 +1,74 @@
+// ParamTLS has limited size. Everything that does not fit is considered fully
+// initialized.
+
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && %run %t
+// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O0 %s -o %t && %run %t
+
+#include <sanitizer/msan_interface.h>
+#include <assert.h>
+
+// This test assumes that ParamTLS size is 800 bytes.
+
+// This test passes poisoned values through function argument list.
+// In case of overflow, argument is unpoisoned.
+#define OVERFLOW(x) assert(__msan_test_shadow(&x, sizeof(x)) == -1)
+// In case of no overflow, it is still poisoned.
+#define NO_OVERFLOW(x) assert(__msan_test_shadow(&x, sizeof(x)) == 0)
+
+template<int N>
+struct S {
+ char x[N];
+};
+
+void f100(S<100> s) {
+ NO_OVERFLOW(s);
+}
+
+void f800(S<800> s) {
+ NO_OVERFLOW(s);
+}
+
+void f801(S<801> s) {
+ OVERFLOW(s);
+}
+
+void f1000(S<1000> s) {
+ OVERFLOW(s);
+}
+
+void f_many(int a, double b, S<800> s, int c, double d) {
+ NO_OVERFLOW(a);
+ NO_OVERFLOW(b);
+ OVERFLOW(s);
+ OVERFLOW(c);
+ OVERFLOW(d);
+}
+
+// -8 bytes for "int a", aligned by 8
+// -2 to make "int c" a partial fit
+void f_many2(int a, S<800 - 8 - 2> s, int c, double d) {
+ NO_OVERFLOW(a);
+ NO_OVERFLOW(s);
+ OVERFLOW(c);
+ OVERFLOW(d);
+}
+
+int main(void) {
+ S<100> s100;
+ S<800> s800;
+ S<801> s801;
+ S<1000> s1000;
+ f100(s100);
+ f800(s800);
+ f801(s801);
+ f1000(s1000);
+
+ int i;
+ double d;
+ f_many(i, d, s800, i, d);
+
+ S<800 - 8 - 2> s788;
+ f_many2(i, s788, i, d);
+ return 0;
+}
diff --git a/test/msan/poison_in_free.cc b/test/msan/poison_in_free.cc
new file mode 100644
index 000000000000..16e2124c3d51
--- /dev/null
+++ b/test/msan/poison_in_free.cc
@@ -0,0 +1,16 @@
+// RUN: %clangxx_msan -O0 %s -o %t && not %run %t >%t.out 2>&1
+// FileCheck %s <%t.out
+// RUN: %clangxx_msan -O0 %s -o %t && MSAN_OPTIONS=poison_in_free=0 %run %t >%t.out 2>&1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char **argv) {
+ char *volatile x = (char*)malloc(50 * sizeof(char));
+ memset(x, 0, 50);
+ free(x);
+ return x[25];
+ // CHECK: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: #0 {{.*}} in main{{.*}}poison_in_free.cc:[[@LINE-2]]
+}
diff --git a/test/msan/print_stats.cc b/test/msan/print_stats.cc
new file mode 100644
index 000000000000..74943835b367
--- /dev/null
+++ b/test/msan/print_stats.cc
@@ -0,0 +1,45 @@
+// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -g %s -o %t
+// RUN: %run %t 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-NOSTATS %s
+// RUN: MSAN_OPTIONS=print_stats=1 %run %t 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-NOSTATS %s
+// RUN: MSAN_OPTIONS=print_stats=1,atexit=1 %run %t 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-STATS %s
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -g -DPOSITIVE=1 %s -o %t
+// RUN: not %run %t 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-NOSTATS %s
+// RUN: MSAN_OPTIONS=print_stats=1 not %run %t 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-STATS %s
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -g -DPOSITIVE=1 -mllvm -msan-keep-going=1 %s -o %t
+// RUN: not %run %t 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-NOSTATS --check-prefix=CHECK-KEEPGOING %s
+// RUN: MSAN_OPTIONS=print_stats=1 not %run %t 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-STATS --check-prefix=CHECK-KEEPGOING %s
+
+#include <stdio.h>
+int main(int argc, char **argv) {
+ int x;
+ int *volatile p = &x;
+ fprintf(stderr, "TEST\n");
+#ifdef POSITIVE
+ return *p;
+#else
+ return 0;
+#endif
+}
+
+// CHECK: TEST
+
+// CHECK-STATS: Unique heap origins:
+// CHECK-STATS: Stack depot allocated bytes:
+// CHECK-STATS: Unique origin histories:
+// CHECK-STATS: History depot allocated bytes:
+
+// CHECK-NOSTATS-NOT: Unique heap origins:
+// CHECK-NOSTATS-NOT: Stack depot allocated bytes:
+// CHECK-NOSTATS-NOT: Unique origin histories:
+// CHECK-NOSTATS-NOT: History depot allocated bytes:
+
+// CHECK-KEEPGOING: MemorySanitizer: 1 warnings reported.
diff --git a/test/msan/pthread_getattr_np_deadlock.cc b/test/msan/pthread_getattr_np_deadlock.cc
new file mode 100644
index 000000000000..07f19cb61b6c
--- /dev/null
+++ b/test/msan/pthread_getattr_np_deadlock.cc
@@ -0,0 +1,22 @@
+// RUN: %clangxx_msan -m64 -fsanitize-memory-track-origins -O0 %s -o %t && %run %t
+
+// Regression test for a deadlock in pthread_getattr_np
+
+#include <assert.h>
+#include <pthread.h>
+
+void *ThreadFn(void *) {
+ pthread_attr_t attr;
+ int res = pthread_getattr_np(pthread_self(), &attr);
+ assert(!res);
+ return 0;
+}
+
+int main(void) {
+ pthread_t t;
+ int res = pthread_create(&t, 0, ThreadFn, 0);
+ assert(!res);
+ res = pthread_join(t, 0);
+ assert(!res);
+ return 0;
+}
diff --git a/test/msan/rand_r.cc b/test/msan/rand_r.cc
new file mode 100644
index 000000000000..d6bdb1deaa68
--- /dev/null
+++ b/test/msan/rand_r.cc
@@ -0,0 +1,18 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O0 -g -DUNINIT %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(void) {
+ unsigned seed;
+#ifndef UNINIT
+ seed = 42;
+#endif
+ int v = rand_r(&seed);
+ // CHECK: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: in main{{.*}}rand_r.cc:[[@LINE-2]]
+ if (v) printf(".\n");
+ return 0;
+}
diff --git a/test/msan/readdir64.cc b/test/msan/readdir64.cc
new file mode 100644
index 000000000000..4f00d1838794
--- /dev/null
+++ b/test/msan/readdir64.cc
@@ -0,0 +1,27 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O1 %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O2 %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t
+
+// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O1 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O2 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t
+// RUN: %clangxx_msan -m64 -O3 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t
+
+// Test that readdir64 is intercepted as well as readdir.
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <stdlib.h>
+
+
+int main(void) {
+ DIR *dir = opendir(".");
+ struct dirent *d = readdir(dir);
+ if (d->d_name[0]) {
+ closedir(dir);
+ exit(0);
+ }
+ closedir(dir);
+ return 0;
+}
diff --git a/test/msan/report-demangling.cc b/test/msan/report-demangling.cc
new file mode 100644
index 000000000000..e6d5c27ec85d
--- /dev/null
+++ b/test/msan/report-demangling.cc
@@ -0,0 +1,19 @@
+// Test that function name is mangled in the "created by an allocation" line,
+// and demangled in the single-frame "stack trace" that follows.
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s < %t.out
+
+__attribute__((noinline))
+int f() {
+ int x;
+ int *volatile p = &x;
+ return *p;
+}
+
+int main(int argc, char **argv) {
+ return f();
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: Uninitialized value was created by an allocation of 'x' in the stack frame of function '_Z1fv'
+ // CHECK: #0 {{.*}} in f() {{.*}}report-demangling.cc:[[@LINE-10]]
+}
diff --git a/test/msan/scandir.cc b/test/msan/scandir.cc
new file mode 100644
index 000000000000..571ba4f603d2
--- /dev/null
+++ b/test/msan/scandir.cc
@@ -0,0 +1,56 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p
+// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p
+
+#include <assert.h>
+#include <glob.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#include <sanitizer/msan_interface.h>
+
+
+static int my_filter(const struct dirent *a) {
+ assert(__msan_test_shadow(&a, sizeof(a)) == (size_t)-1);
+ printf("%s\n", a->d_name);
+ __msan_print_shadow(a, a->d_reclen);
+ assert(__msan_test_shadow(a, a->d_reclen) == (size_t)-1);
+ printf("%s\n", a->d_name);
+ return strlen(a->d_name) == 3 && a->d_name[2] == 'b';
+}
+
+static int my_compar(const struct dirent **a, const struct dirent **b) {
+ assert(__msan_test_shadow(a, sizeof(*a)) == (size_t)-1);
+ assert(__msan_test_shadow(*a, (*a)->d_reclen) == (size_t)-1);
+ assert(__msan_test_shadow(b, sizeof(*b)) == (size_t)-1);
+ assert(__msan_test_shadow(*b, (*b)->d_reclen) == (size_t)-1);
+ if ((*a)->d_name[1] == (*b)->d_name[1])
+ return 0;
+ return ((*a)->d_name[1] < (*b)->d_name[1]) ? 1 : -1;
+}
+
+int main(int argc, char *argv[]) {
+ assert(argc == 2);
+ char buf[1024];
+ snprintf(buf, sizeof(buf), "%s/%s", argv[1], "scandir_test_root/");
+
+ struct dirent **d;
+ int res = scandir(buf, &d, my_filter, my_compar);
+ assert(res == 2);
+ assert(__msan_test_shadow(&d, sizeof(*d)) == (size_t)-1);
+ for (int i = 0; i < res; ++i) {
+ assert(__msan_test_shadow(&d[i], sizeof(d[i])) == (size_t)-1);
+ assert(__msan_test_shadow(d[i], d[i]->d_reclen) == (size_t)-1);
+ }
+
+ assert(strcmp(d[0]->d_name, "bbb") == 0);
+ assert(strcmp(d[1]->d_name, "aab") == 0);
+ return 0;
+}
diff --git a/test/msan/scandir_null.cc b/test/msan/scandir_null.cc
new file mode 100644
index 000000000000..e7663dc43a74
--- /dev/null
+++ b/test/msan/scandir_null.cc
@@ -0,0 +1,34 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t %p
+// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && %run %t %p
+
+#include <assert.h>
+#include <glob.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#include <sanitizer/msan_interface.h>
+
+
+int main(int argc, char *argv[]) {
+ assert(argc == 2);
+ char buf[1024];
+ snprintf(buf, sizeof(buf), "%s/%s", argv[1], "scandir_test_root/");
+
+ struct dirent **d;
+ int res = scandir(buf, &d, NULL, NULL);
+ assert(res >= 3);
+ assert(__msan_test_shadow(&d, sizeof(*d)) == (size_t)-1);
+ for (int i = 0; i < res; ++i) {
+ assert(__msan_test_shadow(&d[i], sizeof(d[i])) == (size_t)-1);
+ assert(__msan_test_shadow(d[i], d[i]->d_reclen) == (size_t)-1);
+ }
+ return 0;
+}
diff --git a/test/msan/scandir_test_root/aaa b/test/msan/scandir_test_root/aaa
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/msan/scandir_test_root/aaa
diff --git a/test/msan/scandir_test_root/aab b/test/msan/scandir_test_root/aab
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/msan/scandir_test_root/aab
diff --git a/test/msan/scandir_test_root/bbb b/test/msan/scandir_test_root/bbb
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/test/msan/scandir_test_root/bbb
diff --git a/test/msan/select.cc b/test/msan/select.cc
new file mode 100644
index 000000000000..89de75ebaaef
--- /dev/null
+++ b/test/msan/select.cc
@@ -0,0 +1,22 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+#include <stdlib.h>
+int main(int argc, char **argv) {
+ int x;
+ int *volatile p = &x;
+ int z = *p ? 1 : 0;
+ if (z)
+ exit(0);
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: {{#0 0x.* in main .*select.cc:}}[[@LINE-3]]
+
+ // CHECK: SUMMARY: MemorySanitizer: use-of-uninitialized-value {{.*select.cc:.* main}}
+ return 0;
+}
diff --git a/test/msan/select_float_origin.cc b/test/msan/select_float_origin.cc
new file mode 100644
index 000000000000..ca8f3a83b0ed
--- /dev/null
+++ b/test/msan/select_float_origin.cc
@@ -0,0 +1,24 @@
+// Regression test for origin propagation in "select i1, float, float".
+// https://code.google.com/p/memory-sanitizer/issues/detail?id=78
+
+// RUN: %clangxx_msan -O2 -fsanitize-memory-track-origins %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+// RUN: %clangxx_msan -O2 -fsanitize-memory-track-origins=2 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+#include <stdio.h>
+#include <sanitizer/msan_interface.h>
+
+int main() {
+ volatile bool b = true;
+ float x, y;
+ __msan_allocated_memory(&x, sizeof(x));
+ __msan_allocated_memory(&y, sizeof(y));
+ float z = b ? x : y;
+ if (z > 0) printf(".\n");
+ // CHECK: Uninitialized value was created by a heap allocation
+ // CHECK: {{#0 0x.* in .*__msan_allocated_memory}}
+ // CHECK: {{#1 0x.* in main .*select_float_origin.cc:}}[[@LINE-6]]
+ return 0;
+}
diff --git a/test/msan/select_origin.cc b/test/msan/select_origin.cc
new file mode 100644
index 000000000000..e832c02e99ce
--- /dev/null
+++ b/test/msan/select_origin.cc
@@ -0,0 +1,22 @@
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+// Test condition origin propagation through "select" IR instruction.
+
+#include <stdio.h>
+#include <stdint.h>
+
+__attribute__((noinline))
+int *max_by_ptr(int *a, int *b) {
+ return *a < *b ? b : a;
+}
+
+int main(void) {
+ int x;
+ int *volatile px = &x;
+ int y = 43;
+ int *p = max_by_ptr(px, &y);
+ // CHECK: Uninitialized value was created by an allocation of 'x' in the stack frame of function 'main'
+ return *p;
+}
diff --git a/test/msan/setlocale.cc b/test/msan/setlocale.cc
new file mode 100644
index 000000000000..b7007f78da7c
--- /dev/null
+++ b/test/msan/setlocale.cc
@@ -0,0 +1,13 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t
+
+#include <assert.h>
+#include <locale.h>
+#include <stdlib.h>
+
+int main(void) {
+ char *locale = setlocale (LC_ALL, "");
+ assert(locale);
+ if (locale[0])
+ exit(0);
+ return 0;
+}
diff --git a/test/msan/signal_stress_test.cc b/test/msan/signal_stress_test.cc
new file mode 100644
index 000000000000..654b9676f4ab
--- /dev/null
+++ b/test/msan/signal_stress_test.cc
@@ -0,0 +1,71 @@
+// RUN: %clangxx_msan -std=c++11 -O0 %s -o %t && %run %t
+
+// Test that va_arg shadow from a signal handler does not leak outside.
+
+#include <signal.h>
+#include <stdarg.h>
+#include <sanitizer/msan_interface.h>
+#include <assert.h>
+#include <sys/time.h>
+#include <stdio.h>
+
+const int kSigCnt = 200;
+
+void f(bool poisoned, int n, ...) {
+ va_list vl;
+ va_start(vl, n);
+ for (int i = 0; i < n; ++i) {
+ void *p = va_arg(vl, void *);
+ if (!poisoned)
+ assert(__msan_test_shadow(&p, sizeof(p)) == -1);
+ }
+ va_end(vl);
+}
+
+int sigcnt;
+
+void SignalHandler(int signo) {
+ assert(signo == SIGPROF);
+ void *p;
+ void **volatile q = &p;
+ f(true, 10,
+ *q, *q, *q, *q, *q,
+ *q, *q, *q, *q, *q);
+ ++sigcnt;
+}
+
+int main() {
+ signal(SIGPROF, SignalHandler);
+
+ itimerval itv;
+ itv.it_interval.tv_sec = 0;
+ itv.it_interval.tv_usec = 100;
+ itv.it_value.tv_sec = 0;
+ itv.it_value.tv_usec = 100;
+ setitimer(ITIMER_PROF, &itv, NULL);
+
+ void *p;
+ void **volatile q = &p;
+
+ do {
+ f(false, 20,
+ nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr);
+ f(true, 20,
+ *q, *q, *q, *q, *q,
+ *q, *q, *q, *q, *q,
+ *q, *q, *q, *q, *q,
+ *q, *q, *q, *q, *q);
+ } while (sigcnt < kSigCnt);
+
+ itv.it_interval.tv_sec = 0;
+ itv.it_interval.tv_usec = 0;
+ itv.it_value.tv_sec = 0;
+ itv.it_value.tv_usec = 0;
+ setitimer(ITIMER_PROF, &itv, NULL);
+
+ signal(SIGPROF, SIG_DFL);
+ return 0;
+}
diff --git a/test/msan/sigwait.cc b/test/msan/sigwait.cc
new file mode 100644
index 000000000000..f2e77cfd6407
--- /dev/null
+++ b/test/msan/sigwait.cc
@@ -0,0 +1,30 @@
+// RUN: %clangxx_msan -std=c++11 -O0 -g %s -o %t && %run %t
+
+#include <assert.h>
+#include <sanitizer/msan_interface.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+void test_sigwait() {
+ sigset_t s;
+ sigemptyset(&s);
+ sigaddset(&s, SIGUSR1);
+ sigprocmask(SIG_BLOCK, &s, 0);
+
+ if (pid_t pid = fork()) {
+ kill(pid, SIGUSR1);
+ _exit(0);
+ } else {
+ int sig;
+ int res = sigwait(&s, &sig);
+ assert(!res);
+ // The following checks that sig is initialized.
+ assert(sig == SIGUSR1);
+ }
+}
+
+int main(void) {
+ test_sigwait();
+ return 0;
+}
diff --git a/test/msan/sigwaitinfo.cc b/test/msan/sigwaitinfo.cc
new file mode 100644
index 000000000000..be7a2c009e0e
--- /dev/null
+++ b/test/msan/sigwaitinfo.cc
@@ -0,0 +1,31 @@
+// RUN: %clangxx_msan -std=c++11 -O0 -g %s -o %t && %run %t
+
+#include <assert.h>
+#include <sanitizer/msan_interface.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+void test_sigwaitinfo() {
+ sigset_t s;
+ sigemptyset(&s);
+ sigaddset(&s, SIGUSR1);
+ sigprocmask(SIG_BLOCK, &s, 0);
+
+ if (pid_t pid = fork()) {
+ kill(pid, SIGUSR1);
+ _exit(0);
+ } else {
+ siginfo_t info;
+ int res = sigwaitinfo(&s, &info);
+ assert(!res);
+ // The following checks that sig is initialized.
+ assert(info.si_signo == SIGUSR1);
+ assert(-1 == __msan_test_shadow(&info, sizeof(info)));
+ }
+}
+
+int main(void) {
+ test_sigwaitinfo();
+ return 0;
+}
diff --git a/test/msan/stack-origin.cc b/test/msan/stack-origin.cc
new file mode 100644
index 000000000000..c39c3a8cf6d0
--- /dev/null
+++ b/test/msan/stack-origin.cc
@@ -0,0 +1,31 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+
+#include <stdlib.h>
+int main(int argc, char **argv) {
+ int x;
+ int *volatile p = &x;
+ return *p;
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: {{#0 0x.* in main .*stack-origin.cc:}}[[@LINE-2]]
+
+ // CHECK-ORIGINS: Uninitialized value was created by an allocation of 'x' in the stack frame of function 'main'
+ // CHECK-ORIGINS: {{#0 0x.* in main .*stack-origin.cc:}}[[@LINE-8]]
+
+ // CHECK: SUMMARY: MemorySanitizer: use-of-uninitialized-value {{.*stack-origin.cc:.* main}}
+}
diff --git a/test/msan/stack-origin2.cc b/test/msan/stack-origin2.cc
new file mode 100644
index 000000000000..0ba57607dadb
--- /dev/null
+++ b/test/msan/stack-origin2.cc
@@ -0,0 +1,41 @@
+// Test that on the second entry to a function the origins are still right.
+
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+
+#include <stdlib.h>
+
+extern "C"
+int f(int depth) {
+ if (depth) return f(depth - 1);
+
+ int x;
+ int *volatile p = &x;
+ return *p;
+}
+
+int main(int argc, char **argv) {
+ return f(1);
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: {{#0 0x.* in main .*stack-origin2.cc:}}[[@LINE-2]]
+
+ // CHECK-ORIGINS: Uninitialized value was created by an allocation of 'x' in the stack frame of function 'f'
+ // CHECK-ORIGINS: {{#0 0x.* in f .*stack-origin2.cc:}}[[@LINE-14]]
+
+ // CHECK: SUMMARY: MemorySanitizer: use-of-uninitialized-value {{.*stack-origin2.cc:.* main}}
+}
diff --git a/test/msan/strerror_r-non-gnu.c b/test/msan/strerror_r-non-gnu.c
new file mode 100644
index 000000000000..d55bf42ef11e
--- /dev/null
+++ b/test/msan/strerror_r-non-gnu.c
@@ -0,0 +1,18 @@
+// RUN: %clang_msan -std=c99 -O0 -g %s -o %t && %run %t
+
+// strerror_r under a weird set of circumstances can be redirected to
+// __xpg_strerror_r. Test that MSan handles this correctly.
+
+#define _POSIX_C_SOURCE 200112
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+int main() {
+ char buf[1000];
+ int res = strerror_r(EINVAL, buf, sizeof(buf));
+ assert(!res);
+ volatile int z = strlen(buf);
+ return 0;
+}
diff --git a/test/msan/strlen_of_shadow.cc b/test/msan/strlen_of_shadow.cc
new file mode 100644
index 000000000000..bb9fe17d41cd
--- /dev/null
+++ b/test/msan/strlen_of_shadow.cc
@@ -0,0 +1,24 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t
+
+// Check that strlen() and similar intercepted functions can be called on shadow
+// memory.
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+const char *mem_to_shadow(const char *p) {
+ return (char *)((uintptr_t)p & ~0x400000000000ULL);
+}
+
+int main(void) {
+ const char *s = "abcdef";
+ assert(strlen(s) == 6);
+ assert(strlen(mem_to_shadow(s)) == 0);
+
+ char *t = new char[42];
+ t[41] = 0;
+ assert(strlen(mem_to_shadow(t)) == 41);
+ return 0;
+}
diff --git a/test/msan/strxfrm.cc b/test/msan/strxfrm.cc
new file mode 100644
index 000000000000..b930a6af69c4
--- /dev/null
+++ b/test/msan/strxfrm.cc
@@ -0,0 +1,15 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t
+
+#include <assert.h>
+#include <sanitizer/msan_interface.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(void) {
+ const char *p = "abcdef";
+ char q[10];
+ size_t n = strxfrm(q, p, sizeof(q));
+ assert(n < sizeof(q));
+ __msan_check_mem_is_initialized(q, n + 1);
+ return 0;
+}
diff --git a/test/msan/sync_lock_set_and_test.cc b/test/msan/sync_lock_set_and_test.cc
new file mode 100644
index 000000000000..b6d344a61340
--- /dev/null
+++ b/test/msan/sync_lock_set_and_test.cc
@@ -0,0 +1,7 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t
+
+int main(void) {
+ int i;
+ __sync_lock_test_and_set(&i, 0);
+ return i;
+}
diff --git a/test/msan/textdomain.cc b/test/msan/textdomain.cc
new file mode 100644
index 000000000000..47e991e8c16b
--- /dev/null
+++ b/test/msan/textdomain.cc
@@ -0,0 +1,12 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t
+
+#include <libintl.h>
+#include <stdio.h>
+
+int main() {
+ const char *td = textdomain("abcd");
+ if (td[0] == 0) {
+ printf("Try read");
+ }
+ return 0;
+}
diff --git a/test/msan/times.cc b/test/msan/times.cc
new file mode 100644
index 000000000000..a042f548dc0c
--- /dev/null
+++ b/test/msan/times.cc
@@ -0,0 +1,20 @@
+// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %run %t
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/times.h>
+
+
+int main(void) {
+ struct tms t;
+ clock_t res = times(&t);
+ assert(res != (clock_t)-1);
+
+ if (t.tms_utime) printf("1\n");
+ if (t.tms_stime) printf("2\n");
+ if (t.tms_cutime) printf("3\n");
+ if (t.tms_cstime) printf("4\n");
+
+ return 0;
+}
diff --git a/test/msan/tls_reuse.cc b/test/msan/tls_reuse.cc
new file mode 100644
index 000000000000..e024a5a8d13f
--- /dev/null
+++ b/test/msan/tls_reuse.cc
@@ -0,0 +1,26 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t
+
+// Check that when TLS block is reused between threads, its shadow is cleaned.
+
+#include <pthread.h>
+#include <stdio.h>
+
+int __thread x;
+
+void *ThreadFn(void *) {
+ if (!x)
+ printf("zzz\n");
+ int y;
+ int * volatile p = &y;
+ x = *p;
+ return 0;
+}
+
+int main(void) {
+ pthread_t t;
+ for (int i = 0; i < 100; ++i) {
+ pthread_create(&t, 0, ThreadFn, 0);
+ pthread_join(t, 0);
+ }
+ return 0;
+}
diff --git a/test/msan/tsearch.cc b/test/msan/tsearch.cc
new file mode 100644
index 000000000000..653dc60371cd
--- /dev/null
+++ b/test/msan/tsearch.cc
@@ -0,0 +1,36 @@
+// RUN: %clangxx_msan -O0 -g %s -o %t && %run %t
+
+#include <assert.h>
+#include <search.h>
+#include <stdlib.h>
+
+int compare(const void *pa, const void *pb) {
+ int a = *(const int *)pa;
+ int b = *(const int *)pb;
+ if (a < b)
+ return -1;
+ else if (a > b)
+ return 1;
+ else
+ return 0;
+}
+
+void myfreenode(void *p) {
+ delete (int *)p;
+}
+
+int main(void) {
+ void *root = NULL;
+ for (int i = 0; i < 5; ++i) {
+ int *p = new int(i);
+ void *q = tsearch(p, &root, compare);
+ if (q == NULL)
+ exit(1);
+ if (*(int **)q != p)
+ delete p;
+ }
+
+ tdestroy(root, myfreenode);
+
+ return 0;
+}
diff --git a/test/msan/tzset.cc b/test/msan/tzset.cc
new file mode 100644
index 000000000000..ed61d7bcc449
--- /dev/null
+++ b/test/msan/tzset.cc
@@ -0,0 +1,16 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+extern char *tzname[2];
+
+int main(void) {
+ if (!strlen(tzname[0]) || !strlen(tzname[1]))
+ exit(1);
+ tzset();
+ if (!strlen(tzname[0]) || !strlen(tzname[1]))
+ exit(1);
+ return 0;
+}
diff --git a/test/msan/unaligned_read_origin.cc b/test/msan/unaligned_read_origin.cc
new file mode 100644
index 000000000000..e5618efbde24
--- /dev/null
+++ b/test/msan/unaligned_read_origin.cc
@@ -0,0 +1,16 @@
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s < %t.out
+
+#include <sanitizer/msan_interface.h>
+
+int main(int argc, char **argv) {
+ int x;
+ int *volatile p = &x;
+ return __sanitizer_unaligned_load32(p);
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: {{#0 0x.* in main .*unaligned_read_origin.cc:}}[[@LINE-2]]
+ // CHECK: Uninitialized value was created by an allocation of 'x' in the stack frame of function 'main'
+ // CHECK: {{#0 0x.* in main .*unaligned_read_origin.cc:}}[[@LINE-7]]
+}
diff --git a/test/msan/unpoison_string.cc b/test/msan/unpoison_string.cc
new file mode 100644
index 000000000000..ac947b9cf6fd
--- /dev/null
+++ b/test/msan/unpoison_string.cc
@@ -0,0 +1,16 @@
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t
+// RUN: %run %t
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O3 %s -o %t
+// RUN: %run %t
+
+#include <assert.h>
+#include <string.h>
+#include <sanitizer/msan_interface.h>
+
+int main(int argc, char **argv) {
+ char s[20] = "string";
+ __msan_poison(s, sizeof(s));
+ __msan_unpoison_string(s);
+ assert(__msan_test_shadow(s, sizeof(s)) == strlen("string") + 1);
+ return 0;
+}
diff --git a/test/msan/use-after-free.cc b/test/msan/use-after-free.cc
new file mode 100644
index 000000000000..5b408c536495
--- /dev/null
+++ b/test/msan/use-after-free.cc
@@ -0,0 +1,34 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out
+
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O1 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O3 %s -o %t && not %run %t >%t.out 2>&1
+// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-ORIGINS < %t.out
+
+#include <stdlib.h>
+int main(int argc, char **argv) {
+ int *volatile p = (int *)malloc(sizeof(int));
+ *p = 42;
+ free(p);
+
+ if (*p)
+ exit(0);
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: {{#0 0x.* in main .*use-after-free.cc:}}[[@LINE-3]]
+
+ // CHECK-ORIGINS: Uninitialized value was created by a heap allocation
+ // CHECK-ORIGINS: {{#0 0x.* in .*free}}
+ // CHECK-ORIGINS: {{#1 0x.* in main .*use-after-free.cc:}}[[@LINE-9]]
+ return 0;
+}
diff --git a/test/msan/vector_cvt.cc b/test/msan/vector_cvt.cc
new file mode 100644
index 000000000000..bd9b6a8b8000
--- /dev/null
+++ b/test/msan/vector_cvt.cc
@@ -0,0 +1,23 @@
+// RUN: %clangxx_msan -m64 -O0 %s -o %t && %run %t
+// RUN: %clangxx_msan -DPOSITIVE -m64 -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+#include <emmintrin.h>
+
+int to_int(double v) {
+ __m128d t = _mm_set_sd(v);
+ int x = _mm_cvtsd_si32(t);
+ return x;
+ // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value
+ // CHECK: #{{.*}} in to_int{{.*}}vector_cvt.cc:[[@LINE-3]]
+}
+
+int main() {
+#ifdef POSITIVE
+ double v;
+#else
+ double v = 1.1;
+#endif
+ double* volatile p = &v;
+ int x = to_int(*p);
+ return !x;
+}
diff --git a/test/msan/vector_select.cc b/test/msan/vector_select.cc
new file mode 100644
index 000000000000..e8d55423293c
--- /dev/null
+++ b/test/msan/vector_select.cc
@@ -0,0 +1,13 @@
+// RUN: %clangxx_msan -m64 -O0 %s -c -o %t
+// RUN: %clangxx_msan -m64 -O3 %s -c -o %t
+
+// Regression test for MemorySanitizer instrumentation of a select instruction
+// with vector arguments.
+
+#include <emmintrin.h>
+
+__m128d select(bool b, __m128d c, __m128d d)
+{
+ return b ? c : d;
+}
+
diff --git a/test/profile/CMakeLists.txt b/test/profile/CMakeLists.txt
new file mode 100644
index 000000000000..28fb35a9f6f8
--- /dev/null
+++ b/test/profile/CMakeLists.txt
@@ -0,0 +1,16 @@
+set(PROFILE_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+set(PROFILE_LIT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
+
+set(PROFILE_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS})
+if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND PROFILE_TEST_DEPS profile llvm-profdata)
+endif()
+
+configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+ )
+add_lit_testsuite(check-profile "Running the profile tests"
+ ${CMAKE_CURRENT_BINARY_DIR}
+ DEPENDS ${PROFILE_TEST_DEPS})
+set_target_properties(check-profile PROPERTIES FOLDER "Profile tests")
diff --git a/test/profile/Inputs/instrprof-dlopen-func.c b/test/profile/Inputs/instrprof-dlopen-func.c
new file mode 100644
index 000000000000..f2de3883535a
--- /dev/null
+++ b/test/profile/Inputs/instrprof-dlopen-func.c
@@ -0,0 +1 @@
+void func(int K) { if (K) {} }
diff --git a/test/profile/Inputs/instrprof-dlopen-func2.c b/test/profile/Inputs/instrprof-dlopen-func2.c
new file mode 100644
index 000000000000..d4d93dc0b256
--- /dev/null
+++ b/test/profile/Inputs/instrprof-dlopen-func2.c
@@ -0,0 +1 @@
+void func2(int K) { if (K) {} }
diff --git a/test/profile/Inputs/instrprof-dlopen-main.c b/test/profile/Inputs/instrprof-dlopen-main.c
new file mode 100644
index 000000000000..ec357fe05bd5
--- /dev/null
+++ b/test/profile/Inputs/instrprof-dlopen-main.c
@@ -0,0 +1,47 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef DLOPEN_FUNC_DIR
+#include <dlfcn.h>
+#else
+void func(int K);
+void func2(int K);
+#endif
+
+int main(int argc, char *argv[]) {
+#ifdef DLOPEN_FUNC_DIR
+ dlerror();
+ void *f1_handle = dlopen(DLOPEN_FUNC_DIR"/func.shared", DLOPEN_FLAGS);
+ if (f1_handle == NULL) {
+ fprintf(stderr, "unable to open '" DLOPEN_FUNC_DIR "/func.shared': %s\n",
+ dlerror());
+ return EXIT_FAILURE;
+ }
+
+ void (*func)(int) = (void (*)(int))dlsym(f1_handle, "func");
+ if (func == NULL) {
+ fprintf(stderr, "unable to lookup symbol 'func': %s\n", dlerror());
+ return EXIT_FAILURE;
+ }
+
+ void *f2_handle = dlopen(DLOPEN_FUNC_DIR"/func2.shared", DLOPEN_FLAGS);
+ if (f2_handle == NULL) {
+ fprintf(stderr, "unable to open '" DLOPEN_FUNC_DIR "/func2.shared': %s\n",
+ dlerror());
+ return EXIT_FAILURE;
+ }
+
+ void (*func2)(int) = (void (*)(int))dlsym(f2_handle, "func2");
+ if (func2 == NULL) {
+ fprintf(stderr, "unable to lookup symbol 'func2': %s\n", dlerror());
+ return EXIT_FAILURE;
+ }
+#endif
+
+ func(1);
+ func2(0);
+
+ return EXIT_SUCCESS;
+}
+
diff --git a/test/profile/Inputs/instrprof-dynamic-a.cpp b/test/profile/Inputs/instrprof-dynamic-a.cpp
new file mode 100644
index 000000000000..67de263c4d88
--- /dev/null
+++ b/test/profile/Inputs/instrprof-dynamic-a.cpp
@@ -0,0 +1,7 @@
+#include "instrprof-dynamic-header.h"
+void a() {
+ if (true) {
+ bar<void>();
+ bar<char>();
+ }
+}
diff --git a/test/profile/Inputs/instrprof-dynamic-b.cpp b/test/profile/Inputs/instrprof-dynamic-b.cpp
new file mode 100644
index 000000000000..c8fb75ef52ed
--- /dev/null
+++ b/test/profile/Inputs/instrprof-dynamic-b.cpp
@@ -0,0 +1,7 @@
+#include "instrprof-dynamic-header.h"
+void b() {
+ if (true) {
+ bar<void>();
+ bar<int>();
+ }
+}
diff --git a/test/profile/Inputs/instrprof-dynamic-header.h b/test/profile/Inputs/instrprof-dynamic-header.h
new file mode 100644
index 000000000000..1dc2e37ef82c
--- /dev/null
+++ b/test/profile/Inputs/instrprof-dynamic-header.h
@@ -0,0 +1,5 @@
+template <class T> void bar() {
+ if (true) {}
+}
+void a();
+void b();
diff --git a/test/profile/Inputs/instrprof-dynamic-main.cpp b/test/profile/Inputs/instrprof-dynamic-main.cpp
new file mode 100644
index 000000000000..0dd60213926e
--- /dev/null
+++ b/test/profile/Inputs/instrprof-dynamic-main.cpp
@@ -0,0 +1,9 @@
+#include "instrprof-dynamic-header.h"
+void foo(int K) { if (K) {} }
+int main(int argc, char *argv[]) {
+ foo(5);
+ bar<void>();
+ a();
+ b();
+ return 0;
+}
diff --git a/test/profile/instrprof-basic.c b/test/profile/instrprof-basic.c
new file mode 100644
index 000000000000..fd3516cfad03
--- /dev/null
+++ b/test/profile/instrprof-basic.c
@@ -0,0 +1,31 @@
+// 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
+
+int begin(int i) {
+ // CHECK: 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]+]]
+ if (i)
+ return 0;
+ return 1;
+}
+
+int main(int argc, const char *argv[]) {
+ begin(0);
+ end(1);
+
+ // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD2:[0-9]+]]
+ if (argc)
+ return 0;
+ return 1;
+}
+
+// CHECK: ![[PD1]] = metadata !{metadata !"branch_weights", i32 1, i32 2}
+// CHECK: ![[PD2]] = metadata !{metadata !"branch_weights", i32 2, i32 1}
diff --git a/test/profile/instrprof-dlopen.test b/test/profile/instrprof-dlopen.test
new file mode 100644
index 000000000000..ba386e34773b
--- /dev/null
+++ b/test/profile/instrprof-dlopen.test
@@ -0,0 +1,34 @@
+RUN: mkdir -p %t.d
+RUN: %clang_profgen -o %t.d/func.shared -fPIC -shared %S/Inputs/instrprof-dlopen-func.c
+RUN: %clang_profgen -o %t.d/func2.shared -fPIC -shared %S/Inputs/instrprof-dlopen-func2.c
+RUN: %clang -o %t-local -fPIC -DDLOPEN_FUNC_DIR=\"%t.d\" -DDLOPEN_FLAGS="RTLD_LAZY | RTLD_LOCAL" %S/Inputs/instrprof-dlopen-main.c
+RUN: %clang -o %t-global -fPIC -DDLOPEN_FUNC_DIR=\"%t.d\" -DDLOPEN_FLAGS="RTLD_LAZY | RTLD_GLOBAL" %S/Inputs/instrprof-dlopen-main.c
+
+RUN: %clang -c -o %t.d/main.o %S/Inputs/instrprof-dlopen-main.c
+RUN: %clang_profgen -o %t-static %S/Inputs/instrprof-dlopen-func.c %S/Inputs/instrprof-dlopen-func2.c %t.d/main.o
+
+RUN: env LLVM_PROFILE_FILE=%t-static.profraw %run %t-static
+RUN: env LLVM_PROFILE_FILE=%t-local.profraw %run %t-local
+RUN: env LLVM_PROFILE_FILE=%t-global.profraw %run %t-global
+
+RUN: llvm-profdata merge -o %t-static.profdata %t-static.profraw
+RUN: llvm-profdata merge -o %t-local.profdata %t-local.profraw
+RUN: llvm-profdata merge -o %t-global.profdata %t-global.profraw
+
+RUN: %clang_profuse=%t-static.profdata -o %t-func.static.ll -S -emit-llvm %S/Inputs/instrprof-dlopen-func.c
+RUN: %clang_profuse=%t-local.profdata -o %t-func.local.ll -S -emit-llvm %S/Inputs/instrprof-dlopen-func.c
+RUN: %clang_profuse=%t-global.profdata -o %t-func.global.ll -S -emit-llvm %S/Inputs/instrprof-dlopen-func.c
+RUN: diff %t-func.static.ll %t-func.local.ll
+RUN: diff %t-func.static.ll %t-func.global.ll
+
+RUN: %clang_profuse=%t-static.profdata -o %t-func2.static.ll -S -emit-llvm %S/Inputs/instrprof-dlopen-func2.c
+RUN: %clang_profuse=%t-local.profdata -o %t-func2.local.ll -S -emit-llvm %S/Inputs/instrprof-dlopen-func2.c
+RUN: %clang_profuse=%t-global.profdata -o %t-func2.global.ll -S -emit-llvm %S/Inputs/instrprof-dlopen-func2.c
+RUN: diff %t-func2.static.ll %t-func2.local.ll
+RUN: diff %t-func2.static.ll %t-func2.global.ll
+
+RUN: %clang_profuse=%t-static.profdata -o %t-main.static.ll -S -emit-llvm %S/Inputs/instrprof-dlopen-main.c
+RUN: %clang_profuse=%t-local.profdata -o %t-main.local.ll -S -emit-llvm %S/Inputs/instrprof-dlopen-main.c
+RUN: %clang_profuse=%t-local.profdata -o %t-main.global.ll -S -emit-llvm %S/Inputs/instrprof-dlopen-main.c
+RUN: diff %t-main.static.ll %t-main.local.ll
+RUN: diff %t-main.static.ll %t-main.global.ll
diff --git a/test/profile/instrprof-dynamic-one-shared.test b/test/profile/instrprof-dynamic-one-shared.test
new file mode 100644
index 000000000000..38be4fe8bc4e
--- /dev/null
+++ b/test/profile/instrprof-dynamic-one-shared.test
@@ -0,0 +1,23 @@
+RUN: mkdir -p %t.d
+RUN: %clang_profgen -o %t.d/a.shared -fPIC -shared %S/Inputs/instrprof-dynamic-a.cpp
+RUN: %clang_profgen -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 -o %t-static %S/Inputs/instrprof-dynamic-a.cpp %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: %clang_profuse=%t-static.profdata -o %t-a.static.ll -S -emit-llvm %S/Inputs/instrprof-dynamic-a.cpp
+RUN: %clang_profuse=%t-shared.profdata -o %t-a.shared.ll -S -emit-llvm %S/Inputs/instrprof-dynamic-a.cpp
+RUN: diff %t-a.static.ll %t-a.shared.ll
+
+RUN: %clang_profuse=%t-static.profdata -o %t-b.static.ll -S -emit-llvm %S/Inputs/instrprof-dynamic-b.cpp
+RUN: %clang_profuse=%t-shared.profdata -o %t-b.shared.ll -S -emit-llvm %S/Inputs/instrprof-dynamic-b.cpp
+RUN: diff %t-b.static.ll %t-b.shared.ll
+
+RUN: %clang_profuse=%t-static.profdata -o %t-main.static.ll -S -emit-llvm %S/Inputs/instrprof-dynamic-main.cpp
+RUN: %clang_profuse=%t-shared.profdata -o %t-main.shared.ll -S -emit-llvm %S/Inputs/instrprof-dynamic-main.cpp
+RUN: diff %t-main.static.ll %t-main.shared.ll
diff --git a/test/profile/instrprof-dynamic-two-shared.test b/test/profile/instrprof-dynamic-two-shared.test
new file mode 100644
index 000000000000..830359dec44f
--- /dev/null
+++ b/test/profile/instrprof-dynamic-two-shared.test
@@ -0,0 +1,24 @@
+RUN: mkdir -p %t.d
+RUN: %clang_profgen -o %t.d/a.shared -fPIC -shared %S/Inputs/instrprof-dynamic-a.cpp
+RUN: %clang_profgen -o %t.d/b.shared -fPIC -shared %S/Inputs/instrprof-dynamic-b.cpp
+RUN: %clang_profgen -o %t-shared -fPIC -rpath %t.d %t.d/a.shared %t.d/b.shared %S/Inputs/instrprof-dynamic-main.cpp
+
+RUN: %clang_profgen -o %t-static %S/Inputs/instrprof-dynamic-a.cpp %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: %clang_profuse=%t-static.profdata -o %t-a.static.ll -S -emit-llvm %S/Inputs/instrprof-dynamic-a.cpp
+RUN: %clang_profuse=%t-shared.profdata -o %t-a.shared.ll -S -emit-llvm %S/Inputs/instrprof-dynamic-a.cpp
+RUN: diff %t-a.static.ll %t-a.shared.ll
+
+RUN: %clang_profuse=%t-static.profdata -o %t-b.static.ll -S -emit-llvm %S/Inputs/instrprof-dynamic-b.cpp
+RUN: %clang_profuse=%t-shared.profdata -o %t-b.shared.ll -S -emit-llvm %S/Inputs/instrprof-dynamic-b.cpp
+RUN: diff %t-b.static.ll %t-b.shared.ll
+
+RUN: %clang_profuse=%t-static.profdata -o %t-main.static.ll -S -emit-llvm %S/Inputs/instrprof-dynamic-main.cpp
+RUN: %clang_profuse=%t-shared.profdata -o %t-main.shared.ll -S -emit-llvm %S/Inputs/instrprof-dynamic-main.cpp
+RUN: diff %t-main.static.ll %t-main.shared.ll
diff --git a/test/profile/instrprof-reset-counters.c b/test/profile/instrprof-reset-counters.c
new file mode 100644
index 000000000000..c92732baf45d
--- /dev/null
+++ b/test/profile/instrprof-reset-counters.c
@@ -0,0 +1,19 @@
+// 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
+
+void __llvm_profile_reset_counters(void);
+void foo(int);
+int main(void) {
+ foo(0);
+ __llvm_profile_reset_counters();
+ foo(1);
+ return 0;
+}
+void foo(int N) {
+ // CHECK-LABEL: define void @foo(
+ // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[FOO:[0-9]+]]
+ if (N) {}
+}
+// CHECK: ![[FOO]] = metadata !{metadata !"branch_weights", i32 2, i32 1}
diff --git a/test/profile/instrprof-set-filename.c b/test/profile/instrprof-set-filename.c
new file mode 100644
index 000000000000..045821899e44
--- /dev/null
+++ b/test/profile/instrprof-set-filename.c
@@ -0,0 +1,14 @@
+// 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
+
+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;
+ __llvm_profile_set_filename(argv[1]);
+ return 0;
+}
+// CHECK: ![[PD1]] = metadata !{metadata !"branch_weights", i32 1, i32 2}
diff --git a/test/profile/instrprof-without-libc.c b/test/profile/instrprof-without-libc.c
new file mode 100644
index 000000000000..60ca9496c611
--- /dev/null
+++ b/test/profile/instrprof-without-libc.c
@@ -0,0 +1,60 @@
+// RUN: %clang_profgen -DCHECK_SYMBOLS -O3 -o %t.symbols %s
+// RUN: llvm-nm %t.symbols | FileCheck %s --check-prefix=CHECK-SYMBOLS
+// RUN: %clang_profgen -O3 -o %t %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
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#ifndef CHECK_SYMBOLS
+#include <stdio.h>
+#endif
+
+int __llvm_profile_runtime = 0;
+uint64_t __llvm_profile_get_size_for_buffer(void);
+int __llvm_profile_write_buffer(char *);
+int write_buffer(uint64_t, const char *);
+int main(int argc, const char *argv[]) {
+ // CHECK-LABEL: define {{.*}} @main(
+ // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD1:[0-9]+]]
+ if (argc < 2)
+ 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;
+ int Write = __llvm_profile_write_buffer(Buffer);
+ if (__llvm_profile_write_buffer(Buffer))
+ return Write;
+
+#ifdef CHECK_SYMBOLS
+ // Don't write it out. Since we're checking the symbols, we don't have libc
+ // available.
+ return 0;
+#else
+ // Actually write it out so we can FileCheck the output.
+ FILE *File = fopen(argv[1], "w");
+ if (!File)
+ return 1;
+ if (fwrite(Buffer, 1, Size, File) != Size)
+ return 1;
+ return fclose(File);
+#endif
+}
+// CHECK: ![[PD1]] = metadata !{metadata !"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: _malloc
+// CHECK-SYMBOLS-NOT: _open
diff --git a/test/profile/instrprof-write-file-atexit-explicitly.c b/test/profile/instrprof-write-file-atexit-explicitly.c
new file mode 100644
index 000000000000..ba229b9144fa
--- /dev/null
+++ b/test/profile/instrprof-write-file-atexit-explicitly.c
@@ -0,0 +1,17 @@
+// 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
+
+int __llvm_profile_runtime = 0;
+int __llvm_profile_register_write_file_atexit(void);
+void __llvm_profile_set_filename(const char *);
+int main(int argc, const char *argv[]) {
+ __llvm_profile_register_write_file_atexit();
+ // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD1:[0-9]+]]
+ if (argc < 2)
+ return 1;
+ __llvm_profile_set_filename(argv[1]);
+ return 0;
+}
+// CHECK: ![[PD1]] = metadata !{metadata !"branch_weights", i32 1, i32 2}
diff --git a/test/profile/instrprof-write-file-only.c b/test/profile/instrprof-write-file-only.c
new file mode 100644
index 000000000000..0dd61de39f1a
--- /dev/null
+++ b/test/profile/instrprof-write-file-only.c
@@ -0,0 +1,35 @@
+// 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
+
+int __llvm_profile_runtime = 0;
+void __llvm_profile_initialize_file(void);
+int __llvm_profile_write_file(void);
+void __llvm_profile_set_filename(const char *);
+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)
+ return 1;
+
+ // Since the runtime has been suppressed, initialize the file name, as the
+ // writing will fail below as the file name has not been specified.
+ __llvm_profile_initialize_file();
+
+ // Write out the profile.
+ __llvm_profile_write_file();
+
+ // Change the profile.
+ return foo(0);
+}
+int foo(int X) {
+ // There should be no profiling information for @foo, since it was called
+ // after the profile was written (and the atexit was suppressed by defining
+ // profile_runtime).
+ // CHECK-LABEL: define {{.*}} @foo(
+ // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{[^,]+$}}
+ return X <= 0 ? -X : X;
+}
+// CHECK: ![[PD1]] = metadata !{metadata !"branch_weights", i32 1, i32 2}
diff --git a/test/profile/instrprof-write-file.c b/test/profile/instrprof-write-file.c
new file mode 100644
index 000000000000..12967cb94a55
--- /dev/null
+++ b/test/profile/instrprof-write-file.c
@@ -0,0 +1,34 @@
+// RUN: %clang_profgen -o %t -O3 %s
+// RUN: env LLVM_PROFILE_FILE=%t1.profraw %run %t %t2.profraw
+// RUN: llvm-profdata merge -o %t1.profdata %t1.profraw
+// RUN: %clang_profuse=%t1.profdata -o - -S -emit-llvm %s | FileCheck %s --check-prefix=CHECK1 --check-prefix=CHECK
+// RUN: llvm-profdata merge -o %t2.profdata %t2.profraw
+// RUN: %clang_profuse=%t2.profdata -o - -S -emit-llvm %s | FileCheck %s --check-prefix=CHECK2 --check-prefix=CHECK
+
+int __llvm_profile_write_file(void);
+void __llvm_profile_set_filename(const char *);
+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 < 2)
+ return 1;
+
+ // Write out the profile.
+ __llvm_profile_write_file();
+
+ // Change the profile.
+ int Ret = foo(0);
+
+ // It'll write out again at exit; change the filename so we get two files.
+ __llvm_profile_set_filename(argv[1]);
+ return Ret;
+}
+int foo(int X) {
+ // CHECK-LABEL: define {{.*}} @foo(
+ // CHECK1: br i1 %{{.*}}, label %{{.*}}, label %{{[^,]+$}}
+ // CHECK2: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD2:[0-9]+]]
+ return X <= 0 ? -X : X;
+}
+// CHECK: ![[PD1]] = metadata !{metadata !"branch_weights", i32 1, i32 2}
+// CHECK2: ![[PD2]] = metadata !{metadata !"branch_weights", i32 2, i32 1}
diff --git a/test/profile/lit.cfg b/test/profile/lit.cfg
new file mode 100644
index 000000000000..e4910abbe7a4
--- /dev/null
+++ b/test/profile/lit.cfg
@@ -0,0 +1,53 @@
+# -*- Python -*-
+
+import os
+
+# Setup config name.
+config.name = 'Profile'
+
+# Setup source root.
+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
+
+# If the above check didn't work, we're probably in the source tree. Use some
+# magic to re-execute from the build tree.
+if config.test_exec_root is None:
+ # The magic relies on knowing compilerrt_site_basedir.
+ compilerrt_basedir = lit_config.params.get('compilerrt_site_basedir', None)
+ if compilerrt_basedir:
+ site_cfg = os.path.join(compilerrt_basedir, 'profile', 'lit.site.cfg')
+ if os.path.exists(site_cfg):
+ lit_config.load_config(config, site_cfg)
+ raise SystemExit
+
+if config.host_os in ['Linux']:
+ extra_linkflags = ["-ldl"]
+else:
+ extra_linkflags = []
+
+# Test suffixes.
+config.suffixes = ['.c', '.cc', '.cpp', '.m', '.mm', '.ll', '.test']
+
+# What to exclude.
+config.excludes = ['Inputs']
+
+# Clang flags.
+clang_cflags = [config.target_cflags] + extra_linkflags
+
+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( ("%clang_profgen ", build_invocation(clang_cflags) + " -fprofile-instr-generate ") )
+config.substitutions.append( ("%clang_profuse=", build_invocation(clang_cflags) + " -fprofile-instr-use=") )
+
+if config.host_os not in ['Darwin', 'FreeBSD', 'Linux']:
+ config.unsupported = True
+
+if config.target_arch in ['armv7l']:
+ config.unsupported = True
diff --git a/test/profile/lit.site.cfg.in b/test/profile/lit.site.cfg.in
new file mode 100644
index 000000000000..758568d6753a
--- /dev/null
+++ b/test/profile/lit.site.cfg.in
@@ -0,0 +1,11 @@
+## Autogenerated by LLVM/Clang configuration.
+# Do not edit!
+
+# Tool-specific config options.
+config.profile_lit_binary_dir = "@PROFILE_LIT_BINARY_DIR@"
+
+# 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, "@PROFILE_LIT_SOURCE_DIR@/lit.cfg")
diff --git a/test/sanitizer_common/CMakeLists.txt b/test/sanitizer_common/CMakeLists.txt
new file mode 100644
index 000000000000..13eecbdc1b2b
--- /dev/null
+++ b/test/sanitizer_common/CMakeLists.txt
@@ -0,0 +1,46 @@
+set(SANITIZER_COMMON_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+
+set(SANITIZER_COMMON_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS})
+set(SANITIZER_COMMON_TESTSUITES)
+
+set(SUPPORTED_TOOLS)
+if(CMAKE_SYSTEM_NAME MATCHES "Darwin|Linux|FreeBSD" AND NOT ANDROID)
+ list(APPEND SUPPORTED_TOOLS asan)
+endif()
+if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT ANDROID)
+ list(APPEND SUPPORTED_TOOLS tsan)
+ list(APPEND SUPPORTED_TOOLS msan)
+ list(APPEND SUPPORTED_TOOLS lsan)
+endif()
+
+# Create a separate config for each tool we support.
+foreach(tool ${SUPPORTED_TOOLS})
+ string(TOUPPER ${tool} tool_toupper)
+ if(${tool_toupper}_SUPPORTED_ARCH)
+ set(SANITIZER_COMMON_LIT_TEST_MODE ${tool})
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/${tool}/lit.site.cfg)
+ list(APPEND SANITIZER_COMMON_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${tool})
+ if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND SANITIZER_COMMON_TEST_DEPS ${tool})
+ endif()
+ endif()
+endforeach()
+
+# Unit tests.
+if(COMPILER_RT_INCLUDE_TESTS)
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg)
+ list(APPEND SANITIZER_COMMON_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit)
+ list(APPEND SANITIZER_COMMON_TEST_DEPS SanitizerUnitTests)
+endif()
+
+if(SANITIZER_COMMON_TESTSUITES)
+ add_lit_testsuite(check-sanitizer "Running sanitizer_common tests"
+ ${SANITIZER_COMMON_TESTSUITES}
+ DEPENDS ${SANITIZER_COMMON_TEST_DEPS})
+ set_target_properties(check-sanitizer PROPERTIES FOLDER
+ "sanitizer_common tests")
+endif()
diff --git a/test/sanitizer_common/TestCases/Linux/aligned_alloc.c b/test/sanitizer_common/TestCases/Linux/aligned_alloc.c
new file mode 100644
index 000000000000..12af18dd32a1
--- /dev/null
+++ b/test/sanitizer_common/TestCases/Linux/aligned_alloc.c
@@ -0,0 +1,8 @@
+// RUN: %clang -std=c11 -O0 %s -o %t && %run %t
+#include <stdlib.h>
+extern void *aligned_alloc (size_t alignment, size_t size);
+int main() {
+ volatile void *p = aligned_alloc(128, 1024);
+ free((void*)p);
+ return 0;
+}
diff --git a/test/sanitizer_common/TestCases/Linux/clock_gettime.c b/test/sanitizer_common/TestCases/Linux/clock_gettime.c
new file mode 100644
index 000000000000..ec1386ef2414
--- /dev/null
+++ b/test/sanitizer_common/TestCases/Linux/clock_gettime.c
@@ -0,0 +1,11 @@
+// RUN: %clang %s -Wl,-as-needed -o %t && %run %t
+// Regression test for PR15823
+// (http://llvm.org/bugs/show_bug.cgi?id=15823).
+#include <stdio.h>
+#include <time.h>
+
+int main() {
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ return 0;
+}
diff --git a/test/sanitizer_common/TestCases/Linux/getpass.cc b/test/sanitizer_common/TestCases/Linux/getpass.cc
new file mode 100644
index 000000000000..c9a2276cc248
--- /dev/null
+++ b/test/sanitizer_common/TestCases/Linux/getpass.cc
@@ -0,0 +1,32 @@
+// RUN: %clangxx -O0 -g %s -lutil -o %t && %run %t | FileCheck %s
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <pty.h>
+
+int
+main (int argc, char** argv)
+{
+ int master;
+ int pid = forkpty(&master, NULL, NULL, NULL);
+
+ if(pid == -1) {
+ fprintf(stderr, "forkpty failed\n");
+ return 1;
+ } else if (pid > 0) {
+ char buf[1024];
+ int res = read(master, buf, sizeof(buf));
+ write(1, buf, res);
+ write(master, "password\n", 9);
+ while ((res = read(master, buf, sizeof(buf))) > 0) write(1, buf, res);
+ } else {
+ char *s = getpass("prompt");
+ assert(strcmp(s, "password") == 0);
+ write(1, "done\n", 5);
+ }
+ return 0;
+}
+
+// CHECK: prompt
+// CHECK: done
diff --git a/test/sanitizer_common/TestCases/Linux/getpwnam_r_invalid_user.cc b/test/sanitizer_common/TestCases/Linux/getpwnam_r_invalid_user.cc
new file mode 100644
index 000000000000..a8b51d7a99c0
--- /dev/null
+++ b/test/sanitizer_common/TestCases/Linux/getpwnam_r_invalid_user.cc
@@ -0,0 +1,19 @@
+// Regression test for a crash in getpwnam_r and similar interceptors.
+// RUN: %clangxx -O0 -g %s -o %t && %run %t
+
+#include <assert.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+int main(void) {
+ struct passwd pwd;
+ struct passwd *pwdres;
+ char buf[10000];
+ int res = getpwnam_r("no-such-user", &pwd, buf, sizeof(buf), &pwdres);
+ assert(res == 0);
+ assert(pwdres == 0);
+ return 0;
+}
diff --git a/test/sanitizer_common/TestCases/Linux/lit.local.cfg b/test/sanitizer_common/TestCases/Linux/lit.local.cfg
new file mode 100644
index 000000000000..57271b8078a4
--- /dev/null
+++ b/test/sanitizer_common/TestCases/Linux/lit.local.cfg
@@ -0,0 +1,9 @@
+def getRoot(config):
+ if not config.parent:
+ return config
+ return getRoot(config.parent)
+
+root = getRoot(config)
+
+if root.host_os not in ['Linux']:
+ config.unsupported = True
diff --git a/test/sanitizer_common/TestCases/Linux/mlock_test.cc b/test/sanitizer_common/TestCases/Linux/mlock_test.cc
new file mode 100644
index 000000000000..69ea7cb91c4f
--- /dev/null
+++ b/test/sanitizer_common/TestCases/Linux/mlock_test.cc
@@ -0,0 +1,13 @@
+// RUN: %clang %s -o %t && %run %t
+// XFAIL: lsan
+
+#include <assert.h>
+#include <sys/mman.h>
+
+int main() {
+ assert(0 == mlockall(MCL_CURRENT));
+ assert(0 == mlock((void *)0x12345, 0x5678));
+ assert(0 == munlockall());
+ assert(0 == munlock((void *)0x987, 0x654));
+}
+
diff --git a/test/sanitizer_common/TestCases/Linux/open_memstream.cc b/test/sanitizer_common/TestCases/Linux/open_memstream.cc
new file mode 100644
index 000000000000..6abe0bfb1483
--- /dev/null
+++ b/test/sanitizer_common/TestCases/Linux/open_memstream.cc
@@ -0,0 +1,57 @@
+// RUN: %clangxx -m64 -O0 -g -xc++ %s -o %t && %run %t
+// RUN: %clangxx -m64 -O3 -g -xc++ %s -o %t && %run %t
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef __has_feature
+#define __has_feature(x) 0
+#endif
+
+#if __has_feature(memory_sanitizer)
+#include <sanitizer/msan_interface.h>
+static void check_mem_is_good(void *p, size_t s) {
+ __msan_check_mem_is_initialized(p, s);
+}
+#elif __has_feature(address_sanitizer)
+#include <sanitizer/asan_interface.h>
+static void check_mem_is_good(void *p, size_t s) {
+ assert(__asan_region_is_poisoned(p, s) == 0);
+}
+#else
+static void check_mem_is_good(void *p, size_t s) {}
+#endif
+
+static void run(void) {
+ char *buf;
+ size_t buf_len;
+ fprintf(stderr, " &buf %p, &buf_len %p\n", &buf, &buf_len);
+ FILE *fp = open_memstream(&buf, &buf_len);
+ fprintf(fp, "hello");
+ fflush(fp);
+ check_mem_is_good(&buf, sizeof(buf));
+ check_mem_is_good(&buf_len, sizeof(buf_len));
+ check_mem_is_good(buf, buf_len);
+
+ char *p = new char[1024];
+ memset(p, 'a', 1023);
+ p[1023] = 0;
+ for (int i = 0; i < 100; ++i)
+ fprintf(fp, "%s", p);
+ delete[] p;
+ fflush(fp);
+ fprintf(stderr, " %p addr %p, len %zu\n", &buf, buf, buf_len);
+ check_mem_is_good(&buf, sizeof(buf));
+ check_mem_is_good(&buf_len, sizeof(buf_len));
+ check_mem_is_good(buf, buf_len);
+ fclose(fp);
+ free(buf);
+}
+
+int main(void) {
+ for (int i = 0; i < 100; ++i)
+ run();
+ return 0;
+}
diff --git a/test/sanitizer_common/TestCases/Linux/ptrace.cc b/test/sanitizer_common/TestCases/Linux/ptrace.cc
new file mode 100644
index 000000000000..2bf0fd2f0f35
--- /dev/null
+++ b/test/sanitizer_common/TestCases/Linux/ptrace.cc
@@ -0,0 +1,60 @@
+// RUN: %clangxx -O0 %s -o %t && %run %t
+
+#include <assert.h>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+int main(void) {
+ pid_t pid;
+ pid = fork();
+ if (pid == 0) { // child
+ ptrace(PTRACE_TRACEME, 0, NULL, NULL);
+ execl("/bin/true", "true", NULL);
+ } else {
+ wait(NULL);
+ int res;
+
+#if __x86_64__
+ user_regs_struct regs;
+ res = ptrace(PTRACE_GETREGS, pid, NULL, &regs);
+ assert(!res);
+ if (regs.rip)
+ printf("%zx\n", regs.rip);
+
+ user_fpregs_struct fpregs;
+ res = ptrace(PTRACE_GETFPREGS, pid, NULL, &fpregs);
+ assert(!res);
+ if (fpregs.mxcsr)
+ printf("%x\n", fpregs.mxcsr);
+#endif // __x86_64__
+
+#if __powerpc64__
+ struct pt_regs regs;
+ res = ptrace((enum __ptrace_request)PTRACE_GETREGS, pid, NULL, &regs);
+ assert(!res);
+ if (regs.nip)
+ printf("%lx\n", regs.nip);
+
+ elf_fpregset_t fpregs;
+ res = ptrace((enum __ptrace_request)PTRACE_GETFPREGS, pid, NULL, &fpregs);
+ assert(!res);
+ if ((elf_greg_t)fpregs[32]) // fpscr
+ printf("%lx\n", (elf_greg_t)fpregs[32]);
+#endif // __powerpc64__
+
+ siginfo_t siginfo;
+ res = ptrace(PTRACE_GETSIGINFO, pid, NULL, &siginfo);
+ assert(!res);
+ assert(siginfo.si_pid == pid);
+
+ ptrace(PTRACE_CONT, pid, NULL, NULL);
+
+ wait(NULL);
+ }
+ return 0;
+}
diff --git a/test/sanitizer_common/TestCases/Linux/timerfd.cc b/test/sanitizer_common/TestCases/Linux/timerfd.cc
new file mode 100644
index 000000000000..e7613bb1d111
--- /dev/null
+++ b/test/sanitizer_common/TestCases/Linux/timerfd.cc
@@ -0,0 +1,52 @@
+// RUN: %clangxx -O0 -g %s -o %t && %run %t | FileCheck %s
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <sys/timerfd.h>
+#include <unistd.h>
+
+int main (int argc, char** argv)
+{
+ int fd = timerfd_create(CLOCK_REALTIME, 0);
+ assert(fd >= 0);
+
+ struct itimerspec its;
+ its.it_value.tv_sec = 0;
+ its.it_value.tv_nsec = 1000000;
+ its.it_interval.tv_sec = its.it_value.tv_sec;
+ its.it_interval.tv_nsec = its.it_value.tv_nsec;
+
+ int res = timerfd_settime(fd, 0, &its, NULL);
+ assert(res != -1);
+
+ struct itimerspec its2;
+ res = timerfd_settime(fd, 0, &its, &its2);
+ assert(res != -1);
+ assert(its2.it_interval.tv_sec == its.it_interval.tv_sec);
+ assert(its2.it_interval.tv_nsec == its.it_interval.tv_nsec);
+ assert(its2.it_value.tv_sec <= its.it_value.tv_sec);
+ assert(its2.it_value.tv_nsec <= its.it_value.tv_nsec);
+
+ struct itimerspec its3;
+ res = timerfd_gettime(fd, &its3);
+ assert(res != -1);
+ assert(its3.it_interval.tv_sec == its.it_interval.tv_sec);
+ assert(its3.it_interval.tv_nsec == its.it_interval.tv_nsec);
+ assert(its3.it_value.tv_sec <= its.it_value.tv_sec);
+ assert(its3.it_value.tv_nsec <= its.it_value.tv_nsec);
+
+
+ unsigned long long buf;
+ res = read(fd, &buf, sizeof(buf));
+ assert(res == 8);
+ assert(buf >= 1);
+
+ res = close(fd);
+ assert(res != -1);
+
+ printf("DONE\n");
+ // CHECK: DONE
+
+ return 0;
+}
diff --git a/test/sanitizer_common/TestCases/corelimit.cc b/test/sanitizer_common/TestCases/corelimit.cc
new file mode 100644
index 000000000000..8f54940d04cc
--- /dev/null
+++ b/test/sanitizer_common/TestCases/corelimit.cc
@@ -0,0 +1,16 @@
+// RUN: %clangxx -O0 %s -o %t && %run %t
+// XFAIL: lsan
+
+#include <assert.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int main() {
+ struct rlimit lim_core;
+ getrlimit(RLIMIT_CORE, &lim_core);
+ void *p;
+ if (sizeof(p) == 8) {
+ assert(0 == lim_core.rlim_max);
+ }
+ return 0;
+}
diff --git a/test/sanitizer_common/TestCases/malloc_hook.cc b/test/sanitizer_common/TestCases/malloc_hook.cc
new file mode 100644
index 000000000000..9702249c57e2
--- /dev/null
+++ b/test/sanitizer_common/TestCases/malloc_hook.cc
@@ -0,0 +1,38 @@
+// RUN: %clangxx -O2 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+// Malloc/free hooks are not supported on Windows.
+// XFAIL: win32
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sanitizer/allocator_interface.h>
+
+extern "C" {
+const volatile void *global_ptr;
+
+// 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"));
+ 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"));
+}
+} // extern "C"
+
+int main() {
+ volatile int *x = new int;
+ // CHECK: MallocHook
+ // Check that malloc hook was called with correct argument.
+ if (global_ptr != (void*)x) {
+ _exit(1);
+ }
+ *x = 0;
+ delete x;
+ // CHECK: FreeHook
+ return 0;
+}
diff --git a/test/sanitizer_common/TestCases/print-stack-trace.cc b/test/sanitizer_common/TestCases/print-stack-trace.cc
new file mode 100644
index 000000000000..1251f67b83cd
--- /dev/null
+++ b/test/sanitizer_common/TestCases/print-stack-trace.cc
@@ -0,0 +1,24 @@
+// RUN: %clangxx -O0 %s -o %t && %tool_options=stack_trace_format=DEFAULT %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx -O3 %s -o %t && %tool_options=stack_trace_format=DEFAULT %run %t 2>&1 | FileCheck %s
+// RUN: %tool_options='stack_trace_format="frame:%n lineno:%l"' %run %t 2>&1 | FileCheck %s --check-prefix=CUSTOM
+// RUN: %tool_options=symbolize_inline_frames=false:stack_trace_format=DEFAULT %run %t 2>&1 | FileCheck %s --check-prefix=NOINLINE
+
+#include <sanitizer/common_interface_defs.h>
+
+static inline void FooBarBaz() {
+ __sanitizer_print_stack_trace();
+}
+
+int main() {
+ FooBarBaz();
+ 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}}
+
+// CUSTOM: frame:1 lineno:9
+// CUSTOM: frame:2 lineno:13
+
+// NOINLINE: #0 0x{{.*}} in __sanitizer_print_stack_trace
+// NOINLINE: #1 0x{{.*}} in main{{.*}}print-stack-trace.cc:9
diff --git a/test/sanitizer_common/TestCases/pthread_mutexattr_get.cc b/test/sanitizer_common/TestCases/pthread_mutexattr_get.cc
new file mode 100644
index 000000000000..26060f395c11
--- /dev/null
+++ b/test/sanitizer_common/TestCases/pthread_mutexattr_get.cc
@@ -0,0 +1,19 @@
+// RUN: %clangxx -O0 %s -o %t && %run %t
+
+#include <assert.h>
+#include <pthread.h>
+
+int main(void) {
+ pthread_mutexattr_t ma;
+ int res = pthread_mutexattr_init(&ma);
+ assert(res == 0);
+ res = pthread_mutexattr_setpshared(&ma, 1);
+ assert(res == 0);
+ int pshared;
+ res = pthread_mutexattr_getpshared(&ma, &pshared);
+ assert(res == 0);
+ assert(pshared == 1);
+ res = pthread_mutexattr_destroy(&ma);
+ assert(res == 0);
+ return 0;
+}
diff --git a/test/sanitizer_common/Unit/lit.site.cfg.in b/test/sanitizer_common/Unit/lit.site.cfg.in
new file mode 100644
index 000000000000..2600585702b2
--- /dev/null
+++ b/test/sanitizer_common/Unit/lit.site.cfg.in
@@ -0,0 +1,15 @@
+## Autogenerated by LLVM/Clang configuration.
+# Do not edit!
+
+# Load common config for all compiler-rt unit tests.
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/unittests/lit.common.unit.configured")
+
+# Setup config name.
+config.name = 'SanitizerCommon-Unit'
+
+# Setup test source and exec root. For unit tests, we define
+# it as build directory with sanitizer_common tests.
+# FIXME: De-hardcode this path.
+config.test_exec_root = os.path.join("@COMPILER_RT_BINARY_DIR@", "lib",
+ "sanitizer_common", "tests")
+config.test_source_root = config.test_exec_root
diff --git a/test/sanitizer_common/lit.common.cfg b/test/sanitizer_common/lit.common.cfg
new file mode 100644
index 000000000000..fb37815ff472
--- /dev/null
+++ b/test/sanitizer_common/lit.common.cfg
@@ -0,0 +1,38 @@
+# -*- Python -*-
+
+# Setup source root.
+config.test_source_root = os.path.join(os.path.dirname(__file__), "TestCases")
+
+config.name = "SanitizerCommon-" + config.tool_name
+
+if config.tool_name == "asan":
+ tool_cflags = ["-fsanitize=address"]
+ tool_options = "ASAN_OPTIONS"
+elif config.tool_name == "tsan":
+ tool_cflags = ["-fsanitize=thread"]
+ tool_options = "TSAN_OPTIONS"
+elif config.tool_name == "msan":
+ tool_cflags = ["-fsanitize=memory"]
+ tool_options = "MSAN_OPTIONS"
+elif config.tool_name == "lsan":
+ tool_cflags = ["-fsanitize=leak"]
+ tool_options = "LSAN_OPTIONS"
+else:
+ lit_config.fatal("Unknown tool for sanitizer_common tests: %r" % config.tool_name)
+
+config.available_features.add(config.tool_name)
+
+clang_cflags = config.debug_info_flags + tool_cflags + [config.target_cflags]
+clang_cxxflags = config.cxx_mode_flags + clang_cflags
+
+def build_invocation(compile_flags):
+ return " " + " ".join([config.clang] + compile_flags) + " "
+
+config.substitutions.append( ("%clang ", build_invocation(clang_cflags)) )
+config.substitutions.append( ("%clangxx ", build_invocation(clang_cxxflags)) )
+config.substitutions.append( ("%tool_options", tool_options) )
+
+config.suffixes = ['.c', '.cc', '.cpp']
+
+if config.host_os not in ['Linux', 'Darwin']:
+ config.unsupported = True
diff --git a/test/sanitizer_common/lit.site.cfg.in b/test/sanitizer_common/lit.site.cfg.in
new file mode 100644
index 000000000000..1e94aa567632
--- /dev/null
+++ b/test/sanitizer_common/lit.site.cfg.in
@@ -0,0 +1,9 @@
+# Load common config for all compiler-rt lit tests.
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")
+
+# Tool-specific config options.
+config.tool_name = "@SANITIZER_COMMON_LIT_TEST_MODE@"
+
+# 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/tsan/CMakeLists.txt b/test/tsan/CMakeLists.txt
new file mode 100644
index 000000000000..29c0821b3c5a
--- /dev/null
+++ b/test/tsan/CMakeLists.txt
@@ -0,0 +1,27 @@
+set(TSAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS})
+if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND TSAN_TEST_DEPS tsan)
+endif()
+if(COMPILER_RT_HAS_LIBCXX_SOURCES AND
+ COMPILER_RT_TEST_COMPILER_ID STREQUAL "Clang")
+ list(APPEND TSAN_TEST_DEPS libcxx_tsan)
+ set(TSAN_HAS_LIBCXX True)
+else()
+ set(TSAN_HAS_LIBCXX False)
+endif()
+
+configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg)
+
+if(COMPILER_RT_INCLUDE_TESTS)
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg)
+ list(APPEND TSAN_TEST_DEPS TsanUnitTests)
+endif()
+
+add_lit_testsuite(check-tsan "Running ThreadSanitizer tests"
+ ${CMAKE_CURRENT_BINARY_DIR}
+ DEPENDS ${TSAN_TEST_DEPS})
+set_target_properties(check-tsan PROPERTIES FOLDER "TSan tests")
diff --git a/test/tsan/Linux/lit.local.cfg b/test/tsan/Linux/lit.local.cfg
new file mode 100644
index 000000000000..57271b8078a4
--- /dev/null
+++ b/test/tsan/Linux/lit.local.cfg
@@ -0,0 +1,9 @@
+def getRoot(config):
+ if not config.parent:
+ return config
+ return getRoot(config.parent)
+
+root = getRoot(config)
+
+if root.host_os not in ['Linux']:
+ config.unsupported = True
diff --git a/test/tsan/Linux/mutex_robust.cc b/test/tsan/Linux/mutex_robust.cc
new file mode 100644
index 000000000000..5ca5e70d49a7
--- /dev/null
+++ b/test/tsan/Linux/mutex_robust.cc
@@ -0,0 +1,36 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+pthread_mutex_t m;
+
+void *thr(void *p) {
+ pthread_mutex_lock(&m);
+ return 0;
+}
+
+int main() {
+ pthread_mutexattr_t a;
+ pthread_mutexattr_init(&a);
+ pthread_mutexattr_setrobust(&a, PTHREAD_MUTEX_ROBUST);
+ pthread_mutex_init(&m, &a);
+ pthread_t th;
+ pthread_create(&th, 0, thr, 0);
+ sleep(1);
+ if (pthread_mutex_lock(&m) != EOWNERDEAD) {
+ fprintf(stderr, "not EOWNERDEAD\n");
+ exit(1);
+ }
+ pthread_join(th, 0);
+ fprintf(stderr, "DONE\n");
+}
+
+// This is a correct code, and tsan must not bark.
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK-NOT: EOWNERDEAD
+// CHECK: DONE
+// CHECK-NOT: WARNING: ThreadSanitizer
+
diff --git a/test/tsan/Linux/mutex_robust2.cc b/test/tsan/Linux/mutex_robust2.cc
new file mode 100644
index 000000000000..0914c1763604
--- /dev/null
+++ b/test/tsan/Linux/mutex_robust2.cc
@@ -0,0 +1,41 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+pthread_mutex_t m;
+int x;
+
+void *thr(void *p) {
+ pthread_mutex_lock(&m);
+ x = 42;
+ return 0;
+}
+
+int main() {
+ pthread_mutexattr_t a;
+ pthread_mutexattr_init(&a);
+ pthread_mutexattr_setrobust(&a, PTHREAD_MUTEX_ROBUST);
+ pthread_mutex_init(&m, &a);
+ pthread_t th;
+ pthread_create(&th, 0, thr, 0);
+ sleep(1);
+ if (pthread_mutex_trylock(&m) != EOWNERDEAD) {
+ fprintf(stderr, "not EOWNERDEAD\n");
+ exit(1);
+ }
+ x = 43;
+ pthread_join(th, 0);
+ fprintf(stderr, "DONE\n");
+}
+
+// This is a false positive, tsan must not bark at the data race.
+// But currently it does.
+// CHECK-NOT: WARNING: ThreadSanitizer WARNING: double lock of mutex
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK-NOT: EOWNERDEAD
+// CHECK: DONE
+// CHECK-NOT: WARNING: ThreadSanitizer
+
diff --git a/test/tsan/Linux/user_fopen.cc b/test/tsan/Linux/user_fopen.cc
new file mode 100644
index 000000000000..c0ff267ff88b
--- /dev/null
+++ b/test/tsan/Linux/user_fopen.cc
@@ -0,0 +1,34 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <stdio.h>
+#include <stdlib.h>
+
+// Defined by tsan.
+extern "C" FILE *__interceptor_fopen(const char *file, const char *mode);
+extern "C" int __interceptor_fileno(FILE *f);
+
+extern "C" FILE *fopen(const char *file, const char *mode) {
+ static int first = 0;
+ if (__sync_lock_test_and_set(&first, 1) == 0)
+ printf("user fopen\n");
+ return __interceptor_fopen(file, mode);
+}
+
+extern "C" int fileno(FILE *f) {
+ static int first = 0;
+ if (__sync_lock_test_and_set(&first, 1) == 0)
+ printf("user fileno\n");
+ return 1;
+}
+
+int main() {
+ FILE *f = fopen("/dev/zero", "r");
+ if (f) {
+ char buf;
+ fread(&buf, 1, 1, f);
+ fclose(f);
+ }
+}
+
+// CHECK: user fopen
+// CHECK-NOT: ThreadSanitizer
+
diff --git a/test/tsan/Linux/user_malloc.cc b/test/tsan/Linux/user_malloc.cc
new file mode 100644
index 000000000000..c671bfcdd17a
--- /dev/null
+++ b/test/tsan/Linux/user_malloc.cc
@@ -0,0 +1,27 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <stdio.h>
+
+// Defined by tsan.
+extern "C" void *__interceptor_malloc(unsigned long size);
+extern "C" void __interceptor_free(void *p);
+
+extern "C" void *malloc(unsigned long size) {
+ static int first = 0;
+ if (__sync_lock_test_and_set(&first, 1) == 0)
+ printf("user malloc\n");
+ return __interceptor_malloc(size);
+}
+
+extern "C" void free(void *p) {
+ __interceptor_free(p);
+}
+
+int main() {
+ volatile char *p = (char*)malloc(10);
+ p[0] = 0;
+ free((void*)p);
+}
+
+// CHECK: user malloc
+// CHECK-NOT: ThreadSanitizer
+
diff --git a/test/tsan/Unit/lit.site.cfg.in b/test/tsan/Unit/lit.site.cfg.in
new file mode 100644
index 000000000000..9498105653a1
--- /dev/null
+++ b/test/tsan/Unit/lit.site.cfg.in
@@ -0,0 +1,14 @@
+## Autogenerated by LLVM/Clang configuration.
+# Do not edit!
+
+# Load common config for all compiler-rt unit tests.
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/unittests/lit.common.unit.configured")
+
+# Setup config name.
+config.name = 'ThreadSanitizer-Unit'
+
+# Setup test source and exec root. For unit tests, we define
+# it as build directory with ASan unit tests.
+# FIXME: De-hardcode this path.
+config.test_exec_root = "@COMPILER_RT_BINARY_DIR@/lib/tsan/tests"
+config.test_source_root = config.test_exec_root
diff --git a/test/tsan/aligned_vs_unaligned_race.cc b/test/tsan/aligned_vs_unaligned_race.cc
new file mode 100644
index 000000000000..f82542ed2b85
--- /dev/null
+++ b/test/tsan/aligned_vs_unaligned_race.cc
@@ -0,0 +1,34 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+// Race between an aligned access and an unaligned access, which
+// touches the same memory region.
+// This is a real race which is not detected by tsan.
+// https://code.google.com/p/thread-sanitizer/issues/detail?id=17
+#include <pthread.h>
+#include <stdio.h>
+#include <stdint.h>
+
+uint64_t Global[2];
+
+void *Thread1(void *x) {
+ Global[1]++;
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ char *p1 = reinterpret_cast<char *>(&Global[0]);
+ uint64_t *p4 = reinterpret_cast<uint64_t *>(p1 + 1);
+ (*p4)++;
+ return NULL;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ printf("Pass\n");
+ // CHECK-NOT: ThreadSanitizer: data race
+ // CHECK: Pass
+ return 0;
+}
diff --git a/test/tsan/allocator_returns_null.cc b/test/tsan/allocator_returns_null.cc
new file mode 100644
index 000000000000..cde706bc8a1d
--- /dev/null
+++ b/test/tsan/allocator_returns_null.cc
@@ -0,0 +1,64 @@
+// Test the behavior of malloc/calloc/realloc when the allocation size is huge.
+// By default (allocator_may_return_null=0) the process should crash.
+// With allocator_may_return_null=1 the allocator should return 0.
+//
+// RUN: %clangxx_tsan -O0 %s -o %t
+// RUN: not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
+// RUN: TSAN_OPTIONS=allocator_may_return_null=0 not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
+// RUN: TSAN_OPTIONS=allocator_may_return_null=0 not %run %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cCRASH
+// RUN: TSAN_OPTIONS=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coCRASH
+// RUN: TSAN_OPTIONS=allocator_may_return_null=0 not %run %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rCRASH
+// RUN: TSAN_OPTIONS=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrCRASH
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <limits>
+int main(int argc, char **argv) {
+ volatile size_t size = std::numeric_limits<size_t>::max() - 10000;
+ assert(argc == 2);
+ char *x = 0;
+ if (!strcmp(argv[1], "malloc")) {
+ fprintf(stderr, "malloc:\n");
+ x = (char*)malloc(size);
+ }
+ if (!strcmp(argv[1], "calloc")) {
+ fprintf(stderr, "calloc:\n");
+ x = (char*)calloc(size / 4, 4);
+ }
+
+ if (!strcmp(argv[1], "calloc-overflow")) {
+ fprintf(stderr, "calloc-overflow:\n");
+ volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max();
+ size_t kArraySize = 4096;
+ volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
+ x = (char*)calloc(kArraySize, kArraySize2);
+ }
+
+ if (!strcmp(argv[1], "realloc")) {
+ fprintf(stderr, "realloc:\n");
+ x = (char*)realloc(0, size);
+ }
+ if (!strcmp(argv[1], "realloc-after-malloc")) {
+ fprintf(stderr, "realloc-after-malloc:\n");
+ char *t = (char*)malloc(100);
+ *t = 42;
+ x = (char*)realloc(t, size);
+ assert(*t == 42);
+ }
+ fprintf(stderr, "x: %p\n", x);
+ return x != 0;
+}
+// CHECK-mCRASH: malloc:
+// CHECK-mCRASH: ThreadSanitizer's allocator is terminating the process
+// CHECK-cCRASH: calloc:
+// CHECK-cCRASH: ThreadSanitizer's allocator is terminating the process
+// CHECK-coCRASH: calloc-overflow:
+// CHECK-coCRASH: ThreadSanitizer's allocator is terminating the process
+// CHECK-rCRASH: realloc:
+// CHECK-rCRASH: ThreadSanitizer's allocator is terminating the process
+// CHECK-mrCRASH: realloc-after-malloc:
+// CHECK-mrCRASH: ThreadSanitizer's allocator is terminating the process
+
diff --git a/test/tsan/atexit.cc b/test/tsan/atexit.cc
new file mode 100644
index 000000000000..69acb4dd783f
--- /dev/null
+++ b/test/tsan/atexit.cc
@@ -0,0 +1,29 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+
+class Logger {
+ public:
+ Logger() {
+ fprintf(stderr, "Logger ctor\n");
+ }
+
+ ~Logger() {
+ fprintf(stderr, "Logger dtor\n");
+ }
+};
+
+Logger logger;
+
+void log_from_atexit() {
+ fprintf(stderr, "In log_from_atexit\n");
+}
+
+int main() {
+ atexit(log_from_atexit);
+}
+
+// CHECK: Logger ctor
+// CHECK: In log_from_atexit
+// CHECK: Logger dtor
diff --git a/test/tsan/atexit2.cc b/test/tsan/atexit2.cc
new file mode 100644
index 000000000000..6f74c5f9f6e5
--- /dev/null
+++ b/test/tsan/atexit2.cc
@@ -0,0 +1,26 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int n;
+const int N = 10000;
+
+static void atexit1() {
+ n++;
+}
+
+static void atexit0() {
+ fprintf(stderr, "run count: %d\n", n);
+}
+
+int main() {
+ atexit(atexit0);
+ for (int i = 0; i < N; i++)
+ atexit(atexit1);
+}
+
+// CHECK-NOT: FATAL: ThreadSanitizer
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: run count: 10000
+
diff --git a/test/tsan/atomic_free.cc b/test/tsan/atomic_free.cc
new file mode 100644
index 000000000000..1dcf887c41d5
--- /dev/null
+++ b/test/tsan/atomic_free.cc
@@ -0,0 +1,19 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <unistd.h>
+
+void *Thread(void *a) {
+ __atomic_fetch_add((int*)a, 1, __ATOMIC_SEQ_CST);
+ return 0;
+}
+
+int main() {
+ int *a = new int(0);
+ pthread_t t;
+ pthread_create(&t, 0, Thread, a);
+ sleep(1);
+ delete a;
+ pthread_join(t, 0);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/atomic_free2.cc b/test/tsan/atomic_free2.cc
new file mode 100644
index 000000000000..c50be6bba940
--- /dev/null
+++ b/test/tsan/atomic_free2.cc
@@ -0,0 +1,19 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <unistd.h>
+
+void *Thread(void *a) {
+ sleep(1);
+ __atomic_fetch_add((int*)a, 1, __ATOMIC_SEQ_CST);
+ return 0;
+}
+
+int main() {
+ int *a = new int(0);
+ pthread_t t;
+ pthread_create(&t, 0, Thread, a);
+ delete a;
+ pthread_join(t, 0);
+}
+
+// CHECK: WARNING: ThreadSanitizer: heap-use-after-free
diff --git a/test/tsan/atomic_norace.cc b/test/tsan/atomic_norace.cc
new file mode 100644
index 000000000000..d9ccda58883c
--- /dev/null
+++ b/test/tsan/atomic_norace.cc
@@ -0,0 +1,61 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+const int kTestCount = 4;
+typedef long long T;
+T atomics[kTestCount * 2];
+
+void Test(int test, T *p, bool main_thread) {
+ volatile T sink;
+ if (test == 0) {
+ if (main_thread)
+ __atomic_fetch_add(p, 1, __ATOMIC_RELAXED);
+ else
+ __atomic_fetch_add(p, 1, __ATOMIC_RELAXED);
+ } else if (test == 1) {
+ if (main_thread)
+ __atomic_exchange_n(p, 1, __ATOMIC_ACQ_REL);
+ else
+ __atomic_exchange_n(p, 1, __ATOMIC_ACQ_REL);
+ } else if (test == 2) {
+ if (main_thread)
+ sink = __atomic_load_n(p, __ATOMIC_SEQ_CST);
+ else
+ __atomic_store_n(p, 1, __ATOMIC_SEQ_CST);
+ } else if (test == 3) {
+ if (main_thread)
+ sink = __atomic_load_n(p, __ATOMIC_SEQ_CST);
+ else
+ sink = *p;
+ }
+}
+
+void *Thread(void *p) {
+ for (int i = 0; i < kTestCount; i++) {
+ Test(i, &atomics[i], false);
+ }
+ sleep(2);
+ for (int i = 0; i < kTestCount; i++) {
+ fprintf(stderr, "Test %d reverse\n", i);
+ Test(i, &atomics[kTestCount + i], false);
+ }
+ return 0;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ sleep(1);
+ for (int i = 0; i < kTestCount; i++) {
+ fprintf(stderr, "Test %d\n", i);
+ Test(i, &atomics[i], true);
+ }
+ for (int i = 0; i < kTestCount; i++) {
+ Test(i, &atomics[kTestCount + i], true);
+ }
+ pthread_join(t, 0);
+}
+
+// CHECK-NOT: ThreadSanitizer: data race
diff --git a/test/tsan/atomic_race.cc b/test/tsan/atomic_race.cc
new file mode 100644
index 000000000000..9cee8ed8272f
--- /dev/null
+++ b/test/tsan/atomic_race.cc
@@ -0,0 +1,80 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <unistd.h>
+#include <stdio.h>
+
+const int kTestCount = 4;
+typedef long long T;
+T atomics[kTestCount * 2];
+
+void Test(int test, T *p, bool main_thread) {
+ volatile T sink;
+ if (test == 0) {
+ if (main_thread)
+ __atomic_fetch_add(p, 1, __ATOMIC_RELAXED);
+ else
+ *p = 42;
+ } else if (test == 1) {
+ if (main_thread)
+ __atomic_fetch_add(p, 1, __ATOMIC_RELAXED);
+ else
+ sink = *p;
+ } else if (test == 2) {
+ if (main_thread)
+ sink = __atomic_load_n(p, __ATOMIC_SEQ_CST);
+ else
+ *p = 42;
+ } else if (test == 3) {
+ if (main_thread)
+ __atomic_store_n(p, 1, __ATOMIC_SEQ_CST);
+ else
+ sink = *p;
+ }
+}
+
+void *Thread(void *p) {
+ for (int i = 0; i < kTestCount; i++) {
+ Test(i, &atomics[i], false);
+ }
+ sleep(4);
+ for (int i = 0; i < kTestCount; i++) {
+ fprintf(stderr, "Test %d reverse\n", i);
+ Test(i, &atomics[kTestCount + i], false);
+ }
+ return 0;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ sleep(1);
+ for (int i = 0; i < kTestCount; i++) {
+ fprintf(stderr, "Test %d\n", i);
+ Test(i, &atomics[i], true);
+ }
+ for (int i = 0; i < kTestCount; i++) {
+ Test(i, &atomics[kTestCount + i], true);
+ }
+ pthread_join(t, 0);
+}
+
+// CHECK: Test 0
+// CHECK: ThreadSanitizer: data race
+// CHECK-NOT: SUMMARY{{.*}}tsan_interface_atomic
+// CHECK: Test 1
+// CHECK: ThreadSanitizer: data race
+// CHECK-NOT: SUMMARY{{.*}}tsan_interface_atomic
+// CHECK: Test 2
+// CHECK: ThreadSanitizer: data race
+// CHECK-NOT: SUMMARY{{.*}}tsan_interface_atomic
+// CHECK: Test 3
+// CHECK: ThreadSanitizer: data race
+// CHECK-NOT: SUMMARY{{.*}}tsan_interface_atomic
+// CHECK: Test 0 reverse
+// CHECK: ThreadSanitizer: data race
+// CHECK: Test 1 reverse
+// CHECK: ThreadSanitizer: data race
+// CHECK: Test 2 reverse
+// CHECK: ThreadSanitizer: data race
+// CHECK: Test 3 reverse
+// CHECK: ThreadSanitizer: data race
diff --git a/test/tsan/atomic_stack.cc b/test/tsan/atomic_stack.cc
new file mode 100644
index 000000000000..7e3176f8e784
--- /dev/null
+++ b/test/tsan/atomic_stack.cc
@@ -0,0 +1,29 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <unistd.h>
+
+int Global;
+
+void *Thread1(void *x) {
+ sleep(1);
+ __atomic_fetch_add(&Global, 1, __ATOMIC_RELAXED);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ Global++;
+ return NULL;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Atomic write of size 4
+// CHECK: #0 __tsan_atomic32_fetch_add
+// CHECK: #1 Thread1
diff --git a/test/tsan/barrier.cc b/test/tsan/barrier.cc
new file mode 100644
index 000000000000..d8c2b6ffe514
--- /dev/null
+++ b/test/tsan/barrier.cc
@@ -0,0 +1,37 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+// CHECK-NOT: ThreadSanitizer: data race
+// CHECK: DONE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <unistd.h>
+
+const int kSize = 4;
+volatile int kIter = 10; // prevent unwinding
+int data[2][kSize];
+pthread_barrier_t barrier;
+
+void *thr(void *p) {
+ int idx = (int)(long)p;
+ for (int i = 0; i < kIter; i++) {
+ int *prev = data[i % 2];
+ int *curr = data[(i + 1) % 2];
+ int left = idx - 1 >= 0 ? prev[idx - 1] : 0;
+ int right = idx + 1 < kSize ? prev[idx + 1] : 0;
+ curr[idx] = (left + right) / 2;
+ pthread_barrier_wait(&barrier);
+ }
+ return 0;
+}
+
+int main() {
+ pthread_barrier_init(&barrier, 0, kSize);
+ pthread_t th[kSize];
+ for (int i = 0; i < kSize; i++)
+ pthread_create(&th[i], 0, thr, (void*)(long)i);
+ for (int i = 0; i < kSize; i++)
+ pthread_join(th[i], 0);
+ pthread_barrier_destroy(&barrier);
+ fprintf(stderr, "DONE\n");
+}
diff --git a/test/tsan/bench.h b/test/tsan/bench.h
new file mode 100644
index 000000000000..5ae0dd813db9
--- /dev/null
+++ b/test/tsan/bench.h
@@ -0,0 +1,59 @@
+#include <pthread.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <time.h>
+
+int bench_nthread;
+int bench_niter;
+int grow_clock_var;
+pthread_barrier_t glow_clock_barrier;
+
+void bench(); // defined by user
+void start_thread_group(int nth, void(*f)(int tid));
+void grow_clock_worker(int tid);
+
+int main(int argc, char **argv) {
+ bench_nthread = 2;
+ if (argc > 1)
+ bench_nthread = atoi(argv[1]);
+ bench_niter = 100;
+ if (argc > 2)
+ bench_niter = atoi(argv[2]);
+
+ // Grow thread's clock.
+ int clock_size = 10;
+ if (argc > 1)
+ clock_size = 1000;
+ pthread_barrier_init(&glow_clock_barrier, 0, clock_size);
+ start_thread_group(clock_size, grow_clock_worker);
+ pthread_barrier_destroy(&glow_clock_barrier);
+ __atomic_load_n(&grow_clock_var, __ATOMIC_ACQUIRE);
+
+ timespec tp0;
+ clock_gettime(CLOCK_MONOTONIC, &tp0);
+ bench();
+ timespec tp1;
+ clock_gettime(CLOCK_MONOTONIC, &tp1);
+ unsigned long long t =
+ (tp1.tv_sec * 1000000000ULL + tp1.tv_nsec) -
+ (tp0.tv_sec * 1000000000ULL + tp0.tv_nsec);
+ fprintf(stderr, "%llu ns/iter\n", t / bench_niter);
+ fprintf(stderr, "DONE\n");
+}
+
+void start_thread_group(int nth, void(*f)(int tid)) {
+ pthread_t *th = (pthread_t*)malloc(nth * sizeof(pthread_t));
+ for (int i = 0; i < nth; i++)
+ pthread_create(&th[i], 0, (void*(*)(void*))f, (void*)(long)i);
+ for (int i = 0; i < nth; i++)
+ pthread_join(th[i], 0);
+}
+
+void grow_clock_worker(int tid) {
+ int res = pthread_barrier_wait(&glow_clock_barrier);
+ if (res == PTHREAD_BARRIER_SERIAL_THREAD)
+ __atomic_store_n(&grow_clock_var, 0, __ATOMIC_RELEASE);
+}
+
diff --git a/test/tsan/bench_acquire_only.cc b/test/tsan/bench_acquire_only.cc
new file mode 100644
index 000000000000..5cd6bd74ebee
--- /dev/null
+++ b/test/tsan/bench_acquire_only.cc
@@ -0,0 +1,19 @@
+// RUN: %clangxx_tsan %s -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#include "bench.h"
+
+int x;
+
+void thread(int tid) {
+ for (int i = 0; i < bench_niter; i++)
+ __atomic_load_n(&x, __ATOMIC_ACQUIRE);
+}
+
+void bench() {
+ __atomic_store_n(&x, 0, __ATOMIC_RELEASE);
+ start_thread_group(bench_nthread, thread);
+}
+
+// CHECK: DONE
+
diff --git a/test/tsan/bench_acquire_release.cc b/test/tsan/bench_acquire_release.cc
new file mode 100644
index 000000000000..9e53a7b26efa
--- /dev/null
+++ b/test/tsan/bench_acquire_release.cc
@@ -0,0 +1,18 @@
+// RUN: %clangxx_tsan %s -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#include "bench.h"
+
+int x;
+
+void thread(int tid) {
+ for (int i = 0; i < bench_niter; i++)
+ __atomic_fetch_add(&x, 1, __ATOMIC_ACQ_REL);
+}
+
+void bench() {
+ start_thread_group(bench_nthread, thread);
+}
+
+// CHECK: DONE
+
diff --git a/test/tsan/bench_local_mutex.cc b/test/tsan/bench_local_mutex.cc
new file mode 100644
index 000000000000..0fa1db0c883c
--- /dev/null
+++ b/test/tsan/bench_local_mutex.cc
@@ -0,0 +1,27 @@
+// RUN: %clangxx_tsan %s -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#include "bench.h"
+
+pthread_mutex_t *mtx;
+const int kStride = 16;
+
+void thread(int tid) {
+ for (int i = 0; i < bench_niter; i++) {
+ pthread_mutex_lock(&mtx[tid * kStride]);
+ pthread_mutex_unlock(&mtx[tid * kStride]);
+ }
+}
+
+void bench() {
+ mtx = (pthread_mutex_t*)malloc(bench_nthread * kStride * sizeof(*mtx));
+ for (int i = 0; i < bench_nthread; i++) {
+ pthread_mutex_init(&mtx[i * kStride], 0);
+ pthread_mutex_lock(&mtx[i * kStride]);
+ pthread_mutex_unlock(&mtx[i * kStride]);
+ }
+ start_thread_group(bench_nthread, thread);
+}
+
+// CHECK: DONE
+
diff --git a/test/tsan/bench_mutex.cc b/test/tsan/bench_mutex.cc
new file mode 100644
index 000000000000..324d53fd7f28
--- /dev/null
+++ b/test/tsan/bench_mutex.cc
@@ -0,0 +1,28 @@
+// RUN: %clangxx_tsan %s -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#include "bench.h"
+
+pthread_mutex_t mtx;
+pthread_cond_t cv;
+int x;
+
+void thread(int tid) {
+ for (int i = 0; i < bench_niter; i++) {
+ pthread_mutex_lock(&mtx);
+ while (x != i * 2 + tid)
+ pthread_cond_wait(&cv, &mtx);
+ x++;
+ pthread_cond_signal(&cv);
+ pthread_mutex_unlock(&mtx);
+ }
+}
+
+void bench() {
+ pthread_mutex_init(&mtx, 0);
+ pthread_cond_init(&cv, 0);
+ start_thread_group(2, thread);
+}
+
+// CHECK: DONE
+
diff --git a/test/tsan/bench_release_only.cc b/test/tsan/bench_release_only.cc
new file mode 100644
index 000000000000..0a86f73f249e
--- /dev/null
+++ b/test/tsan/bench_release_only.cc
@@ -0,0 +1,23 @@
+// RUN: %clangxx_tsan %s -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#include "bench.h"
+
+int *x;
+const int kStride = 32;
+
+void thread(int tid) {
+ __atomic_load_n(&x[tid * kStride], __ATOMIC_ACQUIRE);
+ for (int i = 0; i < bench_niter; i++)
+ __atomic_store_n(&x[tid * kStride], 0, __ATOMIC_RELEASE);
+}
+
+void bench() {
+ x = (int*)malloc(bench_nthread * kStride * sizeof(x[0]));
+ for (int i = 0; i < bench_nthread; i++)
+ __atomic_store_n(&x[i * kStride], 0, __ATOMIC_RELEASE);
+ start_thread_group(bench_nthread, thread);
+}
+
+// CHECK: DONE
+
diff --git a/test/tsan/bench_rwmutex.cc b/test/tsan/bench_rwmutex.cc
new file mode 100644
index 000000000000..818ee8c82bc1
--- /dev/null
+++ b/test/tsan/bench_rwmutex.cc
@@ -0,0 +1,25 @@
+// RUN: %clangxx_tsan %s -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#include "bench.h"
+
+pthread_rwlock_t mtx;
+
+void thread(int tid) {
+ for (int i = 0; i < bench_niter; i++) {
+ pthread_rwlock_rdlock(&mtx);
+ pthread_rwlock_unlock(&mtx);
+ }
+}
+
+void bench() {
+ pthread_rwlock_init(&mtx, 0);
+ pthread_rwlock_wrlock(&mtx);
+ pthread_rwlock_unlock(&mtx);
+ pthread_rwlock_rdlock(&mtx);
+ pthread_rwlock_unlock(&mtx);
+ start_thread_group(bench_nthread, thread);
+}
+
+// CHECK: DONE
+
diff --git a/test/tsan/bench_shadow_flush.cc b/test/tsan/bench_shadow_flush.cc
new file mode 100644
index 000000000000..0f412bbe82f9
--- /dev/null
+++ b/test/tsan/bench_shadow_flush.cc
@@ -0,0 +1,48 @@
+// RUN: %clangxx_tsan %s -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <time.h>
+#include <sys/mman.h>
+
+const long kSmallPage = 4 << 10;
+const long kLargePage = 2 << 20;
+const long kStride = 1 << 10;
+
+typedef unsigned long uptr;
+
+int main(int argc, const char **argv) {
+ uptr mem_size = 4 << 20;
+ if (argc > 1)
+ mem_size = (uptr)atoi(argv[1]) << 20;
+ uptr stride = kSmallPage;
+ if (argc > 2)
+ stride = (uptr)atoi(argv[2]) << 10;
+ int niter = 1;
+ if (argc > 3)
+ niter = atoi(argv[3]);
+ int stride2 = 1;
+ if (argc > 4)
+ stride2 = atoi(argv[4]);
+
+ uptr sz = mem_size + stride2 * kStride + kLargePage;
+ void *p = mmap(0, sz, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
+ uptr a = ((uptr)p + kLargePage - 1) & ~(kLargePage - 1);
+ volatile char *mem = (volatile char *)a;
+
+ for (int i = 0; i < niter; i++) {
+ for (uptr off = 0; off < mem_size; off += stride) {
+ for (uptr off2 = 0; off2 < stride2; off2++)
+ mem[off + off2 * kStride] = 42;
+ }
+ }
+
+ fprintf(stderr, "DONE\n");
+}
+
+// CHECK: DONE
+
diff --git a/test/tsan/bench_single_writer.cc b/test/tsan/bench_single_writer.cc
new file mode 100644
index 000000000000..0d3810a03ad0
--- /dev/null
+++ b/test/tsan/bench_single_writer.cc
@@ -0,0 +1,23 @@
+// RUN: %clangxx_tsan %s -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#include "bench.h"
+
+int x;
+
+void thread(int tid) {
+ if (tid == 0) {
+ for (int i = 0; i < bench_niter; i++)
+ __atomic_store_n(&x, 0, __ATOMIC_RELEASE);
+ } else {
+ for (int i = 0; i < bench_niter; i++)
+ __atomic_load_n(&x, __ATOMIC_ACQUIRE);
+ }
+}
+
+void bench() {
+ start_thread_group(bench_nthread, thread);
+}
+
+// CHECK: DONE
+
diff --git a/test/tsan/bench_ten_mutexes.cc b/test/tsan/bench_ten_mutexes.cc
new file mode 100644
index 000000000000..876f1365ee43
--- /dev/null
+++ b/test/tsan/bench_ten_mutexes.cc
@@ -0,0 +1,26 @@
+// RUN: %clangxx_tsan %s -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#include "bench.h"
+
+const int kMutex = 10;
+pthread_mutex_t mtx[kMutex];
+
+void thread(int tid) {
+ for (int i = 0; i < bench_niter; i++) {
+ int idx = (i % kMutex);
+ if (tid == 0)
+ idx = kMutex - idx - 1;
+ pthread_mutex_lock(&mtx[idx]);
+ pthread_mutex_unlock(&mtx[idx]);
+ }
+}
+
+void bench() {
+ for (int i = 0; i < kMutex; i++)
+ pthread_mutex_init(&mtx[i], 0);
+ start_thread_group(2, thread);
+}
+
+// CHECK: DONE
+
diff --git a/test/tsan/benign_race.cc b/test/tsan/benign_race.cc
new file mode 100644
index 000000000000..b6cba19aa96e
--- /dev/null
+++ b/test/tsan/benign_race.cc
@@ -0,0 +1,39 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+int WTFGlobal;
+
+extern "C" {
+void AnnotateBenignRaceSized(const char *f, int l,
+ void *mem, unsigned int size, const char *desc);
+void WTFAnnotateBenignRaceSized(const char *f, int l,
+ void *mem, unsigned int size,
+ const char *desc);
+}
+
+
+void *Thread(void *x) {
+ Global = 42;
+ WTFGlobal = 142;
+ return 0;
+}
+
+int main() {
+ AnnotateBenignRaceSized(__FILE__, __LINE__,
+ &Global, sizeof(Global), "Race on Global");
+ WTFAnnotateBenignRaceSized(__FILE__, __LINE__,
+ &WTFGlobal, sizeof(WTFGlobal),
+ "Race on WTFGlobal");
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ sleep(1);
+ Global = 43;
+ WTFGlobal = 143;
+ pthread_join(t, 0);
+ printf("OK\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/blacklist.cc b/test/tsan/blacklist.cc
new file mode 100644
index 000000000000..d6ca383cb758
--- /dev/null
+++ b/test/tsan/blacklist.cc
@@ -0,0 +1,30 @@
+// Test blacklist functionality for TSan.
+
+// RUN: echo "fun:*Blacklisted_Thread2*" > %t.blacklist
+// RUN: %clangxx_tsan -O1 %s -fsanitize-blacklist=%t.blacklist -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+
+int Global;
+
+void *Thread1(void *x) {
+ Global++;
+ return NULL;
+}
+
+void *Blacklisted_Thread2(void *x) {
+ Global--;
+ return NULL;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Blacklisted_Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ printf("PASS\n");
+ return 0;
+}
+
+// CHECK-NOT: ThreadSanitizer: data race
diff --git a/test/tsan/blacklist2.cc b/test/tsan/blacklist2.cc
new file mode 100644
index 000000000000..1092561e55bb
--- /dev/null
+++ b/test/tsan/blacklist2.cc
@@ -0,0 +1,49 @@
+// Test that blacklisted functions are still contained in the stack trace.
+
+// RUN: echo "fun:*Blacklisted_Thread2*" > %t.blacklist
+// RUN: echo "fun:*CallTouchGlobal*" >> %t.blacklist
+
+// RUN: %clangxx_tsan -O1 %s -fsanitize-blacklist=%t.blacklist -o %t
+// RUN: %deflake %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+
+void *Thread1(void *x) {
+ sleep(1);
+ // CHECK: ThreadSanitizer: data race
+ // CHECK: Write of size 4
+ // CHECK: #0 Thread1{{.*}}blacklist2.cc:[[@LINE+1]]
+ Global++;
+ return NULL;
+}
+
+void TouchGlobal() {
+ // CHECK: Previous write of size 4
+ // CHECK: #0 TouchGlobal{{.*}}blacklist2.cc:[[@LINE+1]]
+ Global--;
+}
+
+void CallTouchGlobal() {
+ // CHECK: #1 CallTouchGlobal{{.*}}blacklist2.cc:[[@LINE+1]]
+ TouchGlobal();
+}
+
+void *Blacklisted_Thread2(void *x) {
+ Global--;
+ // CHECK: #2 Blacklisted_Thread2{{.*}}blacklist2.cc:[[@LINE+1]]
+ CallTouchGlobal();
+ return NULL;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Blacklisted_Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ printf("PASS\n");
+ return 0;
+}
diff --git a/test/tsan/cond.c b/test/tsan/cond.c
new file mode 100644
index 000000000000..05ea672c6c1c
--- /dev/null
+++ b/test/tsan/cond.c
@@ -0,0 +1,53 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+// CHECK-NOT: ThreadSanitizer WARNING: double lock
+// CHECK-NOT: ThreadSanitizer WARNING: mutex unlock by another thread
+// CHECK: OK
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+pthread_mutex_t m;
+pthread_cond_t c;
+int x;
+
+void *thr1(void *p) {
+ int i;
+
+ for (i = 0; i < 10; i += 2) {
+ pthread_mutex_lock(&m);
+ while (x != i)
+ pthread_cond_wait(&c, &m);
+ x = i + 1;
+ pthread_cond_signal(&c);
+ pthread_mutex_unlock(&m);
+ }
+ return 0;
+}
+
+void *thr2(void *p) {
+ int i;
+
+ for (i = 1; i < 10; i += 2) {
+ pthread_mutex_lock(&m);
+ while (x != i)
+ pthread_cond_wait(&c, &m);
+ x = i + 1;
+ pthread_mutex_unlock(&m);
+ pthread_cond_broadcast(&c);
+ }
+ return 0;
+}
+
+int main() {
+ pthread_t th1, th2;
+
+ pthread_mutex_init(&m, 0);
+ pthread_cond_init(&c, 0);
+ pthread_create(&th1, 0, thr1, 0);
+ pthread_create(&th2, 0, thr2, 0);
+ pthread_join(th1, 0);
+ pthread_join(th2, 0);
+ fprintf(stderr, "OK\n");
+}
diff --git a/test/tsan/cond_cancel.c b/test/tsan/cond_cancel.c
new file mode 100644
index 000000000000..397cad4b1838
--- /dev/null
+++ b/test/tsan/cond_cancel.c
@@ -0,0 +1,37 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+// CHECK-NOT: WARNING
+// CHECK: OK
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <unistd.h>
+
+pthread_mutex_t m;
+pthread_cond_t c;
+int x;
+
+void *thr1(void *p) {
+ pthread_mutex_lock(&m);
+ pthread_cleanup_push((void(*)(void *arg))pthread_mutex_unlock, &m);
+ while (x == 0)
+ pthread_cond_wait(&c, &m);
+ pthread_cleanup_pop(1);
+ return 0;
+}
+
+int main() {
+ pthread_t th;
+
+ pthread_mutex_init(&m, 0);
+ pthread_cond_init(&c, 0);
+
+ pthread_create(&th, 0, thr1, 0);
+ sleep(1); // let it block on cond var
+ pthread_cancel(th);
+
+ pthread_join(th, 0);
+ pthread_mutex_lock(&m);
+ pthread_mutex_unlock(&m);
+ fprintf(stderr, "OK\n");
+}
diff --git a/test/tsan/cond_race.cc b/test/tsan/cond_race.cc
new file mode 100644
index 000000000000..fa42fafca4d2
--- /dev/null
+++ b/test/tsan/cond_race.cc
@@ -0,0 +1,40 @@
+// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+// CHECK-NOT: unlock of unlocked mutex
+// CHECK: ThreadSanitizer: data race
+// CHECK: pthread_cond_signal
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <unistd.h>
+
+struct Ctx {
+ pthread_mutex_t m;
+ pthread_cond_t c;
+ bool done;
+};
+
+void *thr(void *p) {
+ Ctx *c = (Ctx*)p;
+ pthread_mutex_lock(&c->m);
+ c->done = true;
+ pthread_mutex_unlock(&c->m);
+ pthread_cond_signal(&c->c);
+ return 0;
+}
+
+int main() {
+ Ctx *c = new Ctx();
+ pthread_mutex_init(&c->m, 0);
+ pthread_cond_init(&c->c, 0);
+ pthread_t th;
+ pthread_create(&th, 0, thr, c);
+ pthread_mutex_lock(&c->m);
+ while (!c->done)
+ pthread_cond_wait(&c->c, &c->m);
+ pthread_mutex_unlock(&c->m);
+ // w/o this sleep, it can be reported as use-after-free
+ sleep(1);
+ delete c;
+ pthread_join(th, 0);
+}
diff --git a/test/tsan/cond_version.c b/test/tsan/cond_version.c
new file mode 100644
index 000000000000..2282c3ad738d
--- /dev/null
+++ b/test/tsan/cond_version.c
@@ -0,0 +1,44 @@
+// RUN: %clang_tsan -O1 %s -o %t -lrt && %run %t 2>&1 | FileCheck %s
+// Test that pthread_cond is properly intercepted,
+// previously there were issues with versioned symbols.
+// CHECK: OK
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <time.h>
+#include <errno.h>
+
+int main() {
+ typedef unsigned long long u64;
+ pthread_mutex_t m;
+ pthread_cond_t c;
+ pthread_condattr_t at;
+ struct timespec ts0, ts1, ts2;
+ int res;
+ u64 sleep;
+
+ pthread_mutex_init(&m, 0);
+ pthread_condattr_init(&at);
+ pthread_condattr_setclock(&at, CLOCK_MONOTONIC);
+ pthread_cond_init(&c, &at);
+
+ clock_gettime(CLOCK_MONOTONIC, &ts0);
+ ts1 = ts0;
+ ts1.tv_sec += 2;
+
+ pthread_mutex_lock(&m);
+ do {
+ res = pthread_cond_timedwait(&c, &m, &ts1);
+ } while (res == 0);
+ pthread_mutex_unlock(&m);
+
+ clock_gettime(CLOCK_MONOTONIC, &ts2);
+ sleep = (u64)ts2.tv_sec * 1000000000 + ts2.tv_nsec -
+ ((u64)ts0.tv_sec * 1000000000 + ts0.tv_nsec);
+ if (res != ETIMEDOUT)
+ exit(printf("bad return value %d, want %d\n", res, ETIMEDOUT));
+ if (sleep < 1000000000)
+ exit(printf("bad sleep duration %lluns, want %dns\n", sleep, 1000000000));
+ fprintf(stderr, "OK\n");
+}
diff --git a/test/tsan/deadlock_detector_stress_test.cc b/test/tsan/deadlock_detector_stress_test.cc
new file mode 100644
index 000000000000..53624782e07b
--- /dev/null
+++ b/test/tsan/deadlock_detector_stress_test.cc
@@ -0,0 +1,596 @@
+// RUN: %clangxx_tsan %s -o %t -DLockType=PthreadMutex
+// RUN: TSAN_OPTIONS=detect_deadlocks=1 %deflake %run %t | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NOT-SECOND
+// TSAN_OPTIONS="detect_deadlocks=1 second_deadlock_stack=1" %deflake %run %t | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-SECOND
+// RUN: %clangxx_tsan %s -o %t -DLockType=PthreadSpinLock
+// RUN: TSAN_OPTIONS=detect_deadlocks=1 %deflake %run %t | FileCheck %s
+// RUN: %clangxx_tsan %s -o %t -DLockType=PthreadRWLock
+// RUN: TSAN_OPTIONS=detect_deadlocks=1 %deflake %run %t | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-RD
+// RUN: %clangxx_tsan %s -o %t -DLockType=PthreadRecursiveMutex
+// RUN: TSAN_OPTIONS=detect_deadlocks=1 %deflake %run %t | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-REC
+#include <pthread.h>
+#undef NDEBUG
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <new>
+
+#ifndef LockType
+#define LockType PthreadMutex
+#endif
+
+// You can optionally pass [test_number [iter_count]] on command line.
+static int test_number = -1;
+static int iter_count = 100000;
+
+class PthreadMutex {
+ public:
+ explicit PthreadMutex(bool recursive = false) {
+ if (recursive) {
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+ assert(0 == pthread_mutex_init(&mu_, &attr));
+ } else {
+ assert(0 == pthread_mutex_init(&mu_, 0));
+ }
+ }
+ ~PthreadMutex() {
+ assert(0 == pthread_mutex_destroy(&mu_));
+ (void)padding_;
+ }
+ static bool supports_read_lock() { return false; }
+ static bool supports_recursive_lock() { return false; }
+ void lock() { assert(0 == pthread_mutex_lock(&mu_)); }
+ void unlock() { assert(0 == pthread_mutex_unlock(&mu_)); }
+ bool try_lock() { return 0 == pthread_mutex_trylock(&mu_); }
+ void rdlock() { assert(0); }
+ void rdunlock() { assert(0); }
+ bool try_rdlock() { assert(0); }
+
+ private:
+ pthread_mutex_t mu_;
+ char padding_[64 - sizeof(pthread_mutex_t)];
+};
+
+class PthreadRecursiveMutex : public PthreadMutex {
+ public:
+ PthreadRecursiveMutex() : PthreadMutex(true) { }
+ static bool supports_recursive_lock() { return true; }
+};
+
+class PthreadSpinLock {
+ public:
+ PthreadSpinLock() { assert(0 == pthread_spin_init(&mu_, 0)); }
+ ~PthreadSpinLock() {
+ assert(0 == pthread_spin_destroy(&mu_));
+ (void)padding_;
+ }
+ static bool supports_read_lock() { return false; }
+ static bool supports_recursive_lock() { return false; }
+ void lock() { assert(0 == pthread_spin_lock(&mu_)); }
+ void unlock() { assert(0 == pthread_spin_unlock(&mu_)); }
+ bool try_lock() { return 0 == pthread_spin_trylock(&mu_); }
+ void rdlock() { assert(0); }
+ void rdunlock() { assert(0); }
+ bool try_rdlock() { assert(0); }
+
+ private:
+ pthread_spinlock_t mu_;
+ char padding_[64 - sizeof(pthread_spinlock_t)];
+};
+
+class PthreadRWLock {
+ public:
+ PthreadRWLock() { assert(0 == pthread_rwlock_init(&mu_, 0)); }
+ ~PthreadRWLock() {
+ assert(0 == pthread_rwlock_destroy(&mu_));
+ (void)padding_;
+ }
+ static bool supports_read_lock() { return true; }
+ static bool supports_recursive_lock() { return false; }
+ void lock() { assert(0 == pthread_rwlock_wrlock(&mu_)); }
+ void unlock() { assert(0 == pthread_rwlock_unlock(&mu_)); }
+ bool try_lock() { return 0 == pthread_rwlock_trywrlock(&mu_); }
+ void rdlock() { assert(0 == pthread_rwlock_rdlock(&mu_)); }
+ void rdunlock() { assert(0 == pthread_rwlock_unlock(&mu_)); }
+ bool try_rdlock() { return 0 == pthread_rwlock_tryrdlock(&mu_); }
+
+ private:
+ pthread_rwlock_t mu_;
+ char padding_[64 - sizeof(pthread_rwlock_t)];
+};
+
+class LockTest {
+ public:
+ LockTest() : n_(), locks_() {}
+ void Init(size_t n) {
+ n_ = n;
+ locks_ = new LockType*[n_];
+ for (size_t i = 0; i < n_; i++)
+ locks_[i] = new LockType;
+ }
+ ~LockTest() {
+ for (size_t i = 0; i < n_; i++)
+ delete locks_[i];
+ delete [] locks_;
+ }
+ void L(size_t i) {
+ assert(i < n_);
+ locks_[i]->lock();
+ }
+
+ void U(size_t i) {
+ assert(i < n_);
+ locks_[i]->unlock();
+ }
+
+ void RL(size_t i) {
+ assert(i < n_);
+ locks_[i]->rdlock();
+ }
+
+ void RU(size_t i) {
+ assert(i < n_);
+ locks_[i]->rdunlock();
+ }
+
+ void *A(size_t i) {
+ assert(i < n_);
+ return locks_[i];
+ }
+
+ bool T(size_t i) {
+ assert(i < n_);
+ return locks_[i]->try_lock();
+ }
+
+ // Simple lock order onversion.
+ void Test1() {
+ if (test_number > 0 && test_number != 1) return;
+ fprintf(stderr, "Starting Test1\n");
+ // CHECK: Starting Test1
+ Init(5);
+ fprintf(stderr, "Expecting lock inversion: %p %p\n", A(0), A(1));
+ // CHECK: Expecting lock inversion: [[A1:0x[a-f0-9]*]] [[A2:0x[a-f0-9]*]]
+ Lock_0_1();
+ Lock_1_0();
+ // CHECK: WARNING: ThreadSanitizer: lock-order-inversion (potential deadlock)
+ // CHECK: Cycle in lock order graph: [[M1:M[0-9]+]] ([[A1]]) => [[M2:M[0-9]+]] ([[A2]]) => [[M1]]
+ // CHECK: Mutex [[M2]] acquired here while holding mutex [[M1]]
+ // CHECK: #0 pthread_
+ // CHECK-SECOND: Mutex [[M1]] previously acquired by the same thread here:
+ // CHECK-SECOND: #0 pthread_
+ // CHECK-NOT-SECOND: second_deadlock_stack=1 to get more informative warning message
+ // CHECK-NOT-SECOND-NOT: #0 pthread_
+ // CHECK: Mutex [[M1]] acquired here while holding mutex [[M2]]
+ // CHECK: #0 pthread_
+ // CHECK-SECOND: Mutex [[M2]] previously acquired by the same thread here:
+ // CHECK-SECOND: #0 pthread_
+ // CHECK-NOT-SECOND-NOT: #0 pthread_
+ // CHECK-NOT: WARNING: ThreadSanitizer:
+ }
+
+ // Simple lock order inversion with 3 locks.
+ void Test2() {
+ if (test_number > 0 && test_number != 2) return;
+ fprintf(stderr, "Starting Test2\n");
+ // CHECK: Starting Test2
+ Init(5);
+ fprintf(stderr, "Expecting lock inversion: %p %p %p\n", A(0), A(1), A(2));
+ // CHECK: Expecting lock inversion: [[A1:0x[a-f0-9]*]] [[A2:0x[a-f0-9]*]] [[A3:0x[a-f0-9]*]]
+ Lock2(0, 1);
+ Lock2(1, 2);
+ Lock2(2, 0);
+ // CHECK: WARNING: ThreadSanitizer: lock-order-inversion (potential deadlock)
+ // CHECK: Cycle in lock order graph: [[M1:M[0-9]+]] ([[A1]]) => [[M2:M[0-9]+]] ([[A2]]) => [[M3:M[0-9]+]] ([[A3]]) => [[M1]]
+ // CHECK-NOT: WARNING: ThreadSanitizer:
+ }
+
+ // Lock order inversion with lots of new locks created (but not used)
+ // between. Since the new locks are not used we should still detect the
+ // deadlock.
+ void Test3() {
+ if (test_number > 0 && test_number != 3) return;
+ fprintf(stderr, "Starting Test3\n");
+ // CHECK: Starting Test3
+ Init(5);
+ Lock_0_1();
+ L(2);
+ CreateAndDestroyManyLocks();
+ U(2);
+ Lock_1_0();
+ // CHECK: WARNING: ThreadSanitizer: lock-order-inversion (potential deadlock)
+ // CHECK-NOT: WARNING: ThreadSanitizer:
+ }
+
+ // lock l0=>l1; then create and use lots of locks; then lock l1=>l0.
+ // The deadlock epoch should have changed and we should not report anything.
+ void Test4() {
+ if (test_number > 0 && test_number != 4) return;
+ fprintf(stderr, "Starting Test4\n");
+ // CHECK: Starting Test4
+ Init(5);
+ Lock_0_1();
+ L(2);
+ CreateLockUnlockAndDestroyManyLocks();
+ U(2);
+ Lock_1_0();
+ // CHECK-NOT: WARNING: ThreadSanitizer:
+ }
+
+ void Test5() {
+ if (test_number > 0 && test_number != 5) return;
+ fprintf(stderr, "Starting Test5\n");
+ // CHECK: Starting Test5
+ Init(5);
+ RunThreads(&LockTest::Lock_0_1, &LockTest::Lock_1_0);
+ // CHECK: WARNING: ThreadSanitizer: lock-order-inversion
+ // CHECK: Cycle in lock order graph: [[M1:M[0-9]+]] ({{.*}}) => [[M2:M[0-9]+]] ({{.*}}) => [[M1]]
+ // CHECK: Mutex [[M2]] acquired here while holding mutex [[M1]] in thread [[T1:T[0-9]+]]
+ // CHECK: Mutex [[M1]] acquired here while holding mutex [[M2]] in thread [[T2:T[0-9]+]]
+ // CHECK: Thread [[T1]] {{.*}} created by main thread
+ // CHECK: Thread [[T2]] {{.*}} created by main thread
+ // CHECK-NOT: WARNING: ThreadSanitizer:
+ }
+
+ void Test6() {
+ if (test_number > 0 && test_number != 6) return;
+ fprintf(stderr, "Starting Test6: 3 threads lock/unlock private mutexes\n");
+ // CHECK: Starting Test6
+ Init(100);
+ // CHECK-NOT: WARNING: ThreadSanitizer:
+ RunThreads(&LockTest::Lock1_Loop_0, &LockTest::Lock1_Loop_1,
+ &LockTest::Lock1_Loop_2);
+ }
+
+ void Test7() {
+ if (test_number > 0 && test_number != 7) return;
+ fprintf(stderr, "Starting Test7\n");
+ // CHECK: Starting Test7
+ Init(10);
+ L(0); T(1); U(1); U(0);
+ T(1); L(0); U(1); U(0);
+ // CHECK-NOT: WARNING: ThreadSanitizer:
+ fprintf(stderr, "No cycle: 0=>1\n");
+ // CHECK: No cycle: 0=>1
+
+ T(2); L(3); U(3); U(2);
+ L(3); T(2); U(3); U(2);
+ // CHECK-NOT: WARNING: ThreadSanitizer:
+ fprintf(stderr, "No cycle: 2=>3\n");
+ // CHECK: No cycle: 2=>3
+
+ T(4); L(5); U(4); U(5);
+ L(5); L(4); U(4); U(5);
+ // CHECK: WARNING: ThreadSanitizer: lock-order-inversion
+ fprintf(stderr, "Have cycle: 4=>5\n");
+ // CHECK: Have cycle: 4=>5
+
+ L(7); L(6); U(6); U(7);
+ T(6); L(7); U(6); U(7);
+ // CHECK: WARNING: ThreadSanitizer: lock-order-inversion
+ fprintf(stderr, "Have cycle: 6=>7\n");
+ // CHECK: Have cycle: 6=>7
+ }
+
+ void Test8() {
+ if (test_number > 0 && test_number != 8) return;
+ if (!LockType::supports_read_lock()) return;
+ fprintf(stderr, "Starting Test8\n");
+ Init(5);
+ // CHECK-RD: Starting Test8
+ RL(0); L(1); RU(0); U(1);
+ L(1); RL(0); RU(0); U(1);
+ // CHECK-RD: WARNING: ThreadSanitizer: lock-order-inversion
+ fprintf(stderr, "Have cycle: 0=>1\n");
+ // CHECK-RD: Have cycle: 0=>1
+
+ RL(2); RL(3); RU(2); RU(3);
+ RL(3); RL(2); RU(2); RU(3);
+ // CHECK-RD: WARNING: ThreadSanitizer: lock-order-inversion
+ fprintf(stderr, "Have cycle: 2=>3\n");
+ // CHECK-RD: Have cycle: 2=>3
+ }
+
+ void Test9() {
+ if (test_number > 0 && test_number != 9) return;
+ if (!LockType::supports_recursive_lock()) return;
+ fprintf(stderr, "Starting Test9\n");
+ // CHECK-REC: Starting Test9
+ Init(5);
+ L(0); L(0); L(0); L(1); U(1); U(0); U(0); U(0);
+ L(1); L(1); L(1); L(0); U(0); U(1); U(1); U(1);
+ // CHECK-REC: WARNING: ThreadSanitizer: lock-order-inversion
+ }
+
+ void Test10() {
+ if (test_number > 0 && test_number != 10) return;
+ fprintf(stderr, "Starting Test10: 4 threads lock/unlock 4 private mutexes, one under another\n");
+ // CHECK: Starting Test10
+ Init(100);
+ // CHECK-NOT: WARNING: ThreadSanitizer:
+ RunThreads(&LockTest::Test10_Thread1, &LockTest::Test10_Thread2,
+ &LockTest::Test10_Thread3, &LockTest::Test10_Thread4);
+ }
+ void Test10_Thread1() { Test10_Thread(0); }
+ void Test10_Thread2() { Test10_Thread(10); }
+ void Test10_Thread3() { Test10_Thread(20); }
+ void Test10_Thread4() { Test10_Thread(30); }
+ void Test10_Thread(size_t m) {
+ for (int i = 0; i < iter_count; i++) {
+ L(m + 0);
+ L(m + 1);
+ L(m + 2);
+ L(m + 3);
+ U(m + 3);
+ U(m + 2);
+ U(m + 1);
+ U(m + 0);
+ }
+ }
+
+ void Test11() {
+ if (test_number > 0 && test_number != 11) return;
+ fprintf(stderr, "Starting Test11: 4 threads lock/unlock 4 private mutexes, all under another private mutex\n");
+ // CHECK: Starting Test11
+ Init(500);
+ // CHECK-NOT: WARNING: ThreadSanitizer:
+ RunThreads(&LockTest::Test11_Thread1, &LockTest::Test11_Thread2,
+ &LockTest::Test11_Thread3, &LockTest::Test11_Thread4);
+ }
+ void Test11_Thread1() { Test10_Thread(0); }
+ void Test11_Thread2() { Test10_Thread(10); }
+ void Test11_Thread3() { Test10_Thread(20); }
+ void Test11_Thread4() { Test10_Thread(30); }
+ void Test11_Thread(size_t m) {
+ for (int i = 0; i < iter_count; i++) {
+ L(m);
+ L(m + 100);
+ U(m + 100);
+ L(m + 200);
+ U(m + 200);
+ L(m + 300);
+ U(m + 300);
+ L(m + 400);
+ U(m + 500);
+ U(m);
+ }
+ }
+
+ void Test12() {
+ if (test_number > 0 && test_number != 12) return;
+ if (!LockType::supports_read_lock()) return;
+ fprintf(stderr, "Starting Test12: 4 threads read lock/unlock 4 shared mutexes, one under another\n");
+ // CHECK-RD: Starting Test12
+ Init(500);
+ // CHECK-RD-NOT: WARNING: ThreadSanitizer:
+ RunThreads(&LockTest::Test12_Thread, &LockTest::Test12_Thread,
+ &LockTest::Test12_Thread, &LockTest::Test12_Thread);
+ }
+ void Test12_Thread() {
+ for (int i = 0; i < iter_count; i++) {
+ RL(000);
+ RL(100);
+ RL(200);
+ RL(300);
+ RU(300);
+ RU(200);
+ RU(100);
+ RU(000);
+ }
+ }
+
+ void Test13() {
+ if (test_number > 0 && test_number != 13) return;
+ if (!LockType::supports_read_lock()) return;
+ fprintf(stderr, "Starting Test13: 4 threads read lock/unlock 4 shared mutexes, all under another shared mutex\n");
+ // CHECK-RD: Starting Test13
+ Init(500);
+ // CHECK-RD-NOT: WARNING: ThreadSanitizer:
+ RunThreads(&LockTest::Test13_Thread, &LockTest::Test13_Thread,
+ &LockTest::Test13_Thread, &LockTest::Test13_Thread);
+ }
+ void Test13_Thread() {
+ for (int i = 0; i < iter_count; i++) {
+ RL(0);
+ RL(100);
+ RU(100);
+ RL(200);
+ RU(200);
+ RL(300);
+ RU(300);
+ RL(400);
+ RU(400);
+ RU(0);
+ }
+ }
+
+ void Test14() {
+ if (test_number > 0 && test_number != 14) return;
+ fprintf(stderr, "Starting Test14: create lots of locks in 4 threads\n");
+ Init(10);
+ // CHECK-RD: Starting Test14
+ RunThreads(&LockTest::CreateAndDestroyLocksLoop,
+ &LockTest::CreateAndDestroyLocksLoop,
+ &LockTest::CreateAndDestroyLocksLoop,
+ &LockTest::CreateAndDestroyLocksLoop);
+ }
+
+ void Test15() {
+ if (test_number > 0 && test_number != 15) return;
+ if (!LockType::supports_read_lock()) return;
+ fprintf(stderr, "Starting Test15: recursive rlock\n");
+ // DISABLEDCHECK-RD: Starting Test15
+ Init(5);
+ RL(0); RL(0); RU(0); RU(0); // Recusrive reader lock.
+ RL(0); RL(0); RL(0); RU(0); RU(0); RU(0); // Recusrive reader lock.
+ }
+
+ // More detailed output test.
+ void Test16() {
+ if (test_number > 0 && test_number != 16) return;
+ fprintf(stderr, "Starting Test16: detailed output test with two locks\n");
+ // CHECK: Starting Test16
+ // CHECK: WARNING: ThreadSanitizer: lock-order-inversion
+ // CHECK: acquired here while holding mutex
+ // CHECK: LockTest::Acquire1
+ // CHECK-NEXT: LockTest::Acquire_0_then_1
+ // CHECK-SECOND: previously acquired by the same thread here
+ // CHECK-SECOND: LockTest::Acquire0
+ // CHECK-SECOND-NEXT: LockTest::Acquire_0_then_1
+ // CHECK: acquired here while holding mutex
+ // CHECK: LockTest::Acquire0
+ // CHECK-NEXT: LockTest::Acquire_1_then_0
+ // CHECK-SECOND: previously acquired by the same thread here
+ // CHECK-SECOND: LockTest::Acquire1
+ // CHECK-SECOND-NEXT: LockTest::Acquire_1_then_0
+ Init(5);
+ Acquire_0_then_1();
+ U(0); U(1);
+ Acquire_1_then_0();
+ U(0); U(1);
+ }
+
+ // More detailed output test.
+ void Test17() {
+ if (test_number > 0 && test_number != 17) return;
+ fprintf(stderr, "Starting Test17: detailed output test with three locks\n");
+ // CHECK: Starting Test17
+ // CHECK: WARNING: ThreadSanitizer: lock-order-inversion
+ // CHECK: LockTest::Acquire1
+ // CHECK-NEXT: LockTest::Acquire_0_then_1
+ // CHECK: LockTest::Acquire2
+ // CHECK-NEXT: LockTest::Acquire_1_then_2
+ // CHECK: LockTest::Acquire0
+ // CHECK-NEXT: LockTest::Acquire_2_then_0
+ Init(5);
+ Acquire_0_then_1();
+ U(0); U(1);
+ Acquire_1_then_2();
+ U(1); U(2);
+ Acquire_2_then_0();
+ U(0); U(2);
+ }
+
+ __attribute__((noinline)) void Acquire2() { L(2); }
+ __attribute__((noinline)) void Acquire1() { L(1); }
+ __attribute__((noinline)) void Acquire0() { L(0); }
+ __attribute__((noinline)) void Acquire_1_then_0() { Acquire1(); Acquire0(); }
+ __attribute__((noinline)) void Acquire_0_then_1() { Acquire0(); Acquire1(); }
+ __attribute__((noinline)) void Acquire_1_then_2() { Acquire1(); Acquire2(); }
+ __attribute__((noinline)) void Acquire_2_then_0() { Acquire2(); Acquire0(); }
+
+ // This test creates, locks, unlocks and destroys lots of mutexes.
+ void Test18() {
+ if (test_number > 0 && test_number != 18) return;
+ fprintf(stderr, "Starting Test18: create, lock and destroy 4 locks; all in "
+ "4 threads in a loop\n");
+ RunThreads(&LockTest::Test18_Thread, &LockTest::Test18_Thread,
+ &LockTest::Test18_Thread, &LockTest::Test18_Thread);
+ }
+
+ void Test18_Thread() {
+ LockType *l = new LockType[4];
+ for (size_t i = 0; i < iter_count / 100; i++) {
+ for (int i = 0; i < 4; i++) l[i].lock();
+ for (int i = 0; i < 4; i++) l[i].unlock();
+ for (int i = 0; i < 4; i++) l[i].~LockType();
+ for (int i = 0; i < 4; i++) new ((void*)&l[i]) LockType();
+ }
+ delete [] l;
+ }
+
+ private:
+ void Lock2(size_t l1, size_t l2) { L(l1); L(l2); U(l2); U(l1); }
+ void Lock_0_1() { Lock2(0, 1); }
+ void Lock_1_0() { sleep(1); Lock2(1, 0); }
+ void Lock1_Loop(size_t i, size_t n_iter) {
+ for (size_t it = 0; it < n_iter; it++) {
+ // if ((it & (it - 1)) == 0) fprintf(stderr, "%zd", i);
+ L(i);
+ U(i);
+ }
+ // fprintf(stderr, "\n");
+ }
+ void Lock1_Loop_0() { Lock1_Loop(0, iter_count); }
+ void Lock1_Loop_1() { Lock1_Loop(10, iter_count); }
+ void Lock1_Loop_2() { Lock1_Loop(20, iter_count); }
+
+ void CreateAndDestroyManyLocks() {
+ LockType *create_many_locks_but_never_acquire =
+ new LockType[kDeadlockGraphSize];
+ (void)create_many_locks_but_never_acquire;
+ delete [] create_many_locks_but_never_acquire;
+ }
+
+ void CreateAndDestroyLocksLoop() {
+ for (size_t it = 0; it <= iter_count; it++) {
+ LockType some_locks[10];
+ (void)some_locks;
+ }
+ }
+
+ void CreateLockUnlockAndDestroyManyLocks() {
+ LockType many_locks[kDeadlockGraphSize];
+ for (size_t i = 0; i < kDeadlockGraphSize; i++) {
+ many_locks[i].lock();
+ many_locks[i].unlock();
+ }
+ }
+
+ // LockTest Member function callback.
+ struct CB {
+ void (LockTest::*f)();
+ LockTest *lt;
+ };
+
+ // Thread function with CB.
+ static void *Thread(void *param) {
+ CB *cb = (CB*)param;
+ (cb->lt->*cb->f)();
+ return NULL;
+ }
+
+ void RunThreads(void (LockTest::*f1)(), void (LockTest::*f2)(),
+ void (LockTest::*f3)() = 0, void (LockTest::*f4)() = 0) {
+ const int kNumThreads = 4;
+ pthread_t t[kNumThreads];
+ CB cb[kNumThreads] = {{f1, this}, {f2, this}, {f3, this}, {f4, this}};
+ for (int i = 0; i < kNumThreads && cb[i].f; i++)
+ pthread_create(&t[i], 0, Thread, &cb[i]);
+ for (int i = 0; i < kNumThreads && cb[i].f; i++)
+ pthread_join(t[i], 0);
+ }
+
+ static const size_t kDeadlockGraphSize = 4096;
+ size_t n_;
+ LockType **locks_;
+};
+
+int main(int argc, char **argv) {
+ if (argc > 1)
+ test_number = atoi(argv[1]);
+ if (argc > 2)
+ iter_count = atoi(argv[2]);
+ LockTest().Test1();
+ LockTest().Test2();
+ LockTest().Test3();
+ LockTest().Test4();
+ LockTest().Test5();
+ LockTest().Test6();
+ LockTest().Test7();
+ LockTest().Test8();
+ LockTest().Test9();
+ LockTest().Test10();
+ LockTest().Test11();
+ LockTest().Test12();
+ LockTest().Test13();
+ LockTest().Test14();
+ LockTest().Test15();
+ LockTest().Test16();
+ LockTest().Test17();
+ LockTest().Test18();
+ fprintf(stderr, "ALL-DONE\n");
+ // CHECK: ALL-DONE
+}
diff --git a/test/tsan/deep_stack1.cc b/test/tsan/deep_stack1.cc
new file mode 100644
index 000000000000..1d00a0e856d5
--- /dev/null
+++ b/test/tsan/deep_stack1.cc
@@ -0,0 +1,44 @@
+// RUN: %clangxx_tsan -O1 %s -o %t -DORDER1 && %deflake %run %t | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t -DORDER2 && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+volatile int X;
+volatile int N;
+void (*volatile F)();
+
+static void foo() {
+ if (--N == 0)
+ X = 42;
+ else
+ F();
+}
+
+void *Thread(void *p) {
+#ifdef ORDER1
+ sleep(1);
+#endif
+ F();
+ return 0;
+}
+
+int main() {
+ N = 50000;
+ F = foo;
+ pthread_t t;
+ pthread_attr_t a;
+ pthread_attr_init(&a);
+ pthread_attr_setstacksize(&a, N * 256 + (1 << 20));
+ pthread_create(&t, &a, Thread, 0);
+#ifdef ORDER2
+ sleep(1);
+#endif
+ X = 43;
+ pthread_join(t, 0);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: #100 foo
+// We must output suffucuently large stack (at least 100 frames)
+
diff --git a/test/tsan/default_options.cc b/test/tsan/default_options.cc
new file mode 100644
index 000000000000..77bdcd5086ba
--- /dev/null
+++ b/test/tsan/default_options.cc
@@ -0,0 +1,32 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+
+extern "C" const char *__tsan_default_options() {
+ return "report_bugs=0";
+}
+
+int Global;
+
+void *Thread1(void *x) {
+ Global = 42;
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ Global = 43;
+ return NULL;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ fprintf(stderr, "DONE\n");
+ return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+// CHECK: DONE
diff --git a/test/tsan/deflake.bash b/test/tsan/deflake.bash
new file mode 100755
index 000000000000..9731fa53e589
--- /dev/null
+++ b/test/tsan/deflake.bash
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+# This script is used to deflake inherently flaky tsan tests.
+# It is invoked from lit tests as:
+# %deflake mybinary
+# which is then substituted by lit to:
+# $(dirname %s)/deflake.bash mybinary
+# The script runs the target program up to 10 times,
+# until it fails (i.e. produces a race report).
+
+for i in $(seq 1 10); do
+ OUT=`$@ 2>&1`
+ if [[ $? != 0 ]]; then
+ echo "$OUT"
+ exit 0
+ fi
+done
+exit 1
diff --git a/test/tsan/dlclose.cc b/test/tsan/dlclose.cc
new file mode 100644
index 000000000000..1a93fe6617e1
--- /dev/null
+++ b/test/tsan/dlclose.cc
@@ -0,0 +1,58 @@
+// 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
+
+// If we mention TSAN_OPTIONS, the test won't run from test_output.sh script.
+
+// Test case for
+// https://code.google.com/p/thread-sanitizer/issues/detail?id=80
+
+#ifdef BUILD_SO
+
+#include <stdio.h>
+
+extern "C"
+void sofunc() {
+ fprintf(stderr, "HELLO FROM SO\n");
+}
+
+#else // BUILD_SO
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <string>
+
+void *lib;
+void *lib2;
+
+struct Closer {
+ ~Closer() {
+ dlclose(lib);
+ fprintf(stderr, "CLOSED SO\n");
+ }
+};
+static Closer c;
+
+int main(int argc, char *argv[]) {
+ lib = dlopen((std::string(argv[0]) + std::string("-so.so")).c_str(),
+ RTLD_NOW|RTLD_NODELETE);
+ if (lib == 0) {
+ printf("error in dlopen: %s\n", dlerror());
+ return 1;
+ }
+ void *f = dlsym(lib, "sofunc");
+ if (f == 0) {
+ printf("error in dlsym: %s\n", dlerror());
+ return 1;
+ }
+ ((void(*)())f)();
+ return 0;
+}
+
+#endif // BUILD_SO
+
+// CHECK: HELLO FROM SO
+// CHECK-NOT: Inconsistency detected by ld.so
+// CHECK: CLOSED SO
+
diff --git a/test/tsan/fd_close_norace.cc b/test/tsan/fd_close_norace.cc
new file mode 100644
index 000000000000..7238d64b432b
--- /dev/null
+++ b/test/tsan/fd_close_norace.cc
@@ -0,0 +1,33 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+void *Thread1(void *x) {
+ int f = open("/dev/random", O_RDONLY);
+ close(f);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ sleep(1);
+ int f = open("/dev/random", O_RDONLY);
+ close(f);
+ return NULL;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ printf("OK\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+
+
diff --git a/test/tsan/fd_close_norace2.cc b/test/tsan/fd_close_norace2.cc
new file mode 100644
index 000000000000..bf94fd5512b3
--- /dev/null
+++ b/test/tsan/fd_close_norace2.cc
@@ -0,0 +1,30 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int pipes[2];
+
+void *Thread(void *x) {
+ // wait for shutown signal
+ while (read(pipes[0], &x, 1) != 1) {
+ }
+ close(pipes[0]);
+ close(pipes[1]);
+ return 0;
+}
+
+int main() {
+ if (pipe(pipes))
+ return 1;
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ // send shutdown signal
+ while (write(pipes[1], &t, 1) != 1) {
+ }
+ pthread_join(t, 0);
+ printf("OK\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+// CHECK: OK
diff --git a/test/tsan/fd_dup_norace.cc b/test/tsan/fd_dup_norace.cc
new file mode 100644
index 000000000000..5045325b22b5
--- /dev/null
+++ b/test/tsan/fd_dup_norace.cc
@@ -0,0 +1,34 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+int fds[2];
+
+void *Thread1(void *x) {
+ char buf;
+ read(fds[0], &buf, 1);
+ close(fds[0]);
+ return 0;
+}
+
+void *Thread2(void *x) {
+ close(fds[1]);
+ return 0;
+}
+
+int main() {
+ fds[0] = open("/dev/random", O_RDONLY);
+ fds[1] = dup2(fds[0], 100);
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ printf("OK\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/fd_location.cc b/test/tsan/fd_location.cc
new file mode 100644
index 000000000000..535329e06409
--- /dev/null
+++ b/test/tsan/fd_location.cc
@@ -0,0 +1,33 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int fds[2];
+
+void *Thread1(void *x) {
+ write(fds[1], "a", 1);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ sleep(1);
+ close(fds[0]);
+ close(fds[1]);
+ return NULL;
+}
+
+int main() {
+ pipe(fds);
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Location is file descriptor {{[0-9]+}} created by main thread at:
+// CHECK: #0 pipe
+// CHECK: #1 main
+
diff --git a/test/tsan/fd_pipe_norace.cc b/test/tsan/fd_pipe_norace.cc
new file mode 100644
index 000000000000..b434703d782a
--- /dev/null
+++ b/test/tsan/fd_pipe_norace.cc
@@ -0,0 +1,33 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int fds[2];
+int X;
+
+void *Thread1(void *x) {
+ X = 42;
+ write(fds[1], "a", 1);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ char buf;
+ while (read(fds[0], &buf, 1) != 1) {
+ }
+ X = 43;
+ return NULL;
+}
+
+int main() {
+ pipe(fds);
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ printf("OK\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/fd_pipe_race.cc b/test/tsan/fd_pipe_race.cc
new file mode 100644
index 000000000000..88c4ed4aa398
--- /dev/null
+++ b/test/tsan/fd_pipe_race.cc
@@ -0,0 +1,37 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int fds[2];
+
+void *Thread1(void *x) {
+ write(fds[1], "a", 1);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ sleep(1);
+ close(fds[0]);
+ close(fds[1]);
+ return NULL;
+}
+
+int main() {
+ pipe(fds);
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Write of size 8
+// CHECK: #0 close
+// CHECK: #1 Thread2
+// CHECK: Previous read of size 8
+// CHECK: #0 write
+// CHECK: #1 Thread1
+
+
diff --git a/test/tsan/fd_socket_connect_norace.cc b/test/tsan/fd_socket_connect_norace.cc
new file mode 100644
index 000000000000..ab2a950f17d6
--- /dev/null
+++ b/test/tsan/fd_socket_connect_norace.cc
@@ -0,0 +1,45 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+struct sockaddr_in addr;
+int X;
+
+void *ClientThread(void *x) {
+ int c = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ X = 42;
+ if (connect(c, (struct sockaddr*)&addr, sizeof(addr))) {
+ perror("connect");
+ exit(1);
+ }
+ close(c);
+ return NULL;
+}
+
+int main() {
+ int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ addr.sin_family = AF_INET;
+ inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);
+ addr.sin_port = INADDR_ANY;
+ socklen_t len = sizeof(addr);
+ bind(s, (sockaddr*)&addr, len);
+ getsockname(s, (sockaddr*)&addr, &len);
+ listen(s, 10);
+ pthread_t t;
+ pthread_create(&t, 0, ClientThread, 0);
+ int c = accept(s, 0, 0);
+ X = 42;
+ pthread_join(t, 0);
+ close(c);
+ close(s);
+ printf("OK\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+
diff --git a/test/tsan/fd_socket_norace.cc b/test/tsan/fd_socket_norace.cc
new file mode 100644
index 000000000000..0f41c4357354
--- /dev/null
+++ b/test/tsan/fd_socket_norace.cc
@@ -0,0 +1,52 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+struct sockaddr_in addr;
+int X;
+
+void *ClientThread(void *x) {
+ X = 42;
+ int c = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (connect(c, (struct sockaddr*)&addr, sizeof(addr))) {
+ perror("connect");
+ exit(1);
+ }
+ if (send(c, "a", 1, 0) != 1) {
+ perror("send");
+ exit(1);
+ }
+ close(c);
+ return NULL;
+}
+
+int main() {
+ int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ addr.sin_family = AF_INET;
+ inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);
+ addr.sin_port = INADDR_ANY;
+ socklen_t len = sizeof(addr);
+ bind(s, (sockaddr*)&addr, len);
+ getsockname(s, (sockaddr*)&addr, &len);
+ listen(s, 10);
+ pthread_t t;
+ pthread_create(&t, 0, ClientThread, 0);
+ int c = accept(s, 0, 0);
+ char buf;
+ while (read(c, &buf, 1) != 1) {
+ }
+ X = 43;
+ close(c);
+ close(s);
+ pthread_join(t, 0);
+ printf("OK\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+
diff --git a/test/tsan/fd_socketpair_norace.cc b/test/tsan/fd_socketpair_norace.cc
new file mode 100644
index 000000000000..a455d44a3965
--- /dev/null
+++ b/test/tsan/fd_socketpair_norace.cc
@@ -0,0 +1,37 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+int fds[2];
+int X;
+
+void *Thread1(void *x) {
+ X = 42;
+ write(fds[1], "a", 1);
+ close(fds[1]);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ char buf;
+ while (read(fds[0], &buf, 1) != 1) {
+ }
+ X = 43;
+ close(fds[0]);
+ return NULL;
+}
+
+int main() {
+ socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ printf("OK\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/fd_stdout_race.cc b/test/tsan/fd_stdout_race.cc
new file mode 100644
index 000000000000..d6a2c7c796f1
--- /dev/null
+++ b/test/tsan/fd_stdout_race.cc
@@ -0,0 +1,41 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+int X;
+
+void *Thread1(void *x) {
+ sleep(1);
+ int f = open("/dev/random", O_RDONLY);
+ char buf;
+ read(f, &buf, 1);
+ close(f);
+ X = 42;
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ X = 43;
+ write(STDOUT_FILENO, "a", 1);
+ return NULL;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Write of size 4
+// CHECK: #0 Thread1
+// CHECK: Previous write of size 4
+// CHECK: #0 Thread2
+
+
diff --git a/test/tsan/fork_atexit.cc b/test/tsan/fork_atexit.cc
new file mode 100644
index 000000000000..6801d3ffff7e
--- /dev/null
+++ b/test/tsan/fork_atexit.cc
@@ -0,0 +1,37 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && TSAN_OPTIONS="atexit_sleep_ms=50" %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+void foo() {
+ printf("CHILD ATEXIT\n");
+}
+
+void *worker(void *unused) {
+ return 0;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, NULL, worker, NULL);
+ int pid = fork();
+ if (pid == 0) {
+ // child
+ atexit(foo);
+ fprintf(stderr, "CHILD DONE\n");
+ } else {
+ pthread_join(t, 0);
+ if (waitpid(pid, 0, 0) == -1) {
+ perror("waitpid");
+ exit(1);
+ }
+ fprintf(stderr, "PARENT DONE\n");
+ }
+}
+
+// CHECK: CHILD DONE
+// CHECK: CHILD ATEXIT
+// CHECK: PARENT DONE
diff --git a/test/tsan/fork_deadlock.cc b/test/tsan/fork_deadlock.cc
new file mode 100644
index 000000000000..cc5b12214cf9
--- /dev/null
+++ b/test/tsan/fork_deadlock.cc
@@ -0,0 +1,48 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && TSAN_OPTIONS="atexit_sleep_ms=50" %run %t 2>&1 | FileCheck %s
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+int counter;
+
+static void *incrementer(void *p) {
+ for (;;)
+ __sync_fetch_and_add(&counter, 1);
+ return 0;
+}
+
+static void *watchdog(void *p) {
+ sleep(100);
+ fprintf(stderr, "timed out after 100 seconds\n");
+ exit(1);
+ return 0;
+}
+
+int main() {
+ pthread_t th1, th2;
+ pthread_create(&th1, 0, incrementer, 0);
+ pthread_create(&th2, 0, watchdog, 0);
+ for (int i = 0; i < 10; i++) {
+ switch (fork()) {
+ default: // parent
+ while (wait(0) < 0) {}
+ fprintf(stderr, ".");
+ break;
+ case 0: // child
+ __sync_fetch_and_add(&counter, 1);
+ exit(0);
+ break;
+ case -1: // error
+ fprintf(stderr, "failed to fork (%d)\n", errno);
+ exit(1);
+ }
+ }
+ fprintf(stderr, "OK\n");
+}
+
+// CHECK: OK
+
diff --git a/test/tsan/fork_multithreaded.cc b/test/tsan/fork_multithreaded.cc
new file mode 100644
index 000000000000..5176a14d6a65
--- /dev/null
+++ b/test/tsan/fork_multithreaded.cc
@@ -0,0 +1,42 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s -check-prefix=CHECK-DIE
+// RUN: %clangxx_tsan -O1 %s -o %t && TSAN_OPTIONS="die_after_fork=0" %run %t 2>&1 | FileCheck %s -check-prefix=CHECK-NODIE
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+static void *sleeper(void *p) {
+ sleep(10);
+ return 0;
+}
+
+int main() {
+ pthread_t th;
+ pthread_create(&th, 0, sleeper, 0);
+ switch (fork()) {
+ default: // parent
+ while (wait(0) < 0) {}
+ break;
+ case 0: // child
+ {
+ pthread_t th2;
+ pthread_create(&th2, 0, sleeper, 0);
+ exit(0);
+ break;
+ }
+ case -1: // error
+ fprintf(stderr, "failed to fork (%d)\n", errno);
+ exit(1);
+ }
+ fprintf(stderr, "OK\n");
+}
+
+// CHECK-DIE: ThreadSanitizer: starting new threads after multi-threaded fork is not supported
+// CHECK-DIE: OK
+
+// CHECK-NODIE-NOT: ThreadSanitizer: starting new threads after multi-threaded fork is not supported
+// CHECK-NODIE: OK
+
diff --git a/test/tsan/fork_multithreaded3.cc b/test/tsan/fork_multithreaded3.cc
new file mode 100644
index 000000000000..a651b3c18b4e
--- /dev/null
+++ b/test/tsan/fork_multithreaded3.cc
@@ -0,0 +1,40 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+static void *racer(void *p) {
+ *(int*)p = 42;
+ return 0;
+}
+
+int main() {
+ switch (fork()) {
+ default: // parent
+ while (wait(0) < 0) {}
+ break;
+ case 0: // child
+ {
+ int x = 0;
+ pthread_t th1, th2;
+ pthread_create(&th1, 0, racer, &x);
+ pthread_create(&th2, 0, racer, &x);
+ pthread_join(th1, 0);
+ pthread_join(th2, 0);
+ exit(0);
+ break;
+ }
+ case -1: // error
+ fprintf(stderr, "failed to fork (%d)\n", errno);
+ exit(1);
+ }
+ fprintf(stderr, "OK\n");
+}
+
+// CHECK: ThreadSanitizer: data race
+// CHECK: OK
+
diff --git a/test/tsan/free_race.c b/test/tsan/free_race.c
new file mode 100644
index 000000000000..663d7bcf2eb9
--- /dev/null
+++ b/test/tsan/free_race.c
@@ -0,0 +1,49 @@
+// RUN: %clang_tsan -O1 %s -o %t
+// RUN: %deflake %run %t | FileCheck %s --check-prefix=CHECK-NOZUPP
+// RUN: TSAN_OPTIONS="suppressions=%s.supp print_suppressions=1" %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-SUPP
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+
+int *mem;
+pthread_mutex_t mtx;
+
+void *Thread1(void *x) {
+ pthread_mutex_lock(&mtx);
+ free(mem);
+ pthread_mutex_unlock(&mtx);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ sleep(1);
+ pthread_mutex_lock(&mtx);
+ mem[0] = 42;
+ pthread_mutex_unlock(&mtx);
+ return NULL;
+}
+
+int main() {
+ mem = (int*)malloc(100);
+ pthread_mutex_init(&mtx, 0);
+ pthread_t t;
+ pthread_create(&t, NULL, Thread1, NULL);
+ Thread2(0);
+ pthread_join(t, NULL);
+ pthread_mutex_destroy(&mtx);
+ return 0;
+}
+
+// CHECK-NOZUPP: WARNING: ThreadSanitizer: heap-use-after-free
+// CHECK-NOZUPP: Write of size 4 at {{.*}} by main thread{{.*}}:
+// CHECK-NOZUPP: #0 Thread2
+// CHECK-NOZUPP: #1 main
+// CHECK-NOZUPP: Previous write of size 8 at {{.*}} by thread T1{{.*}}:
+// CHECK-NOZUPP: #0 free
+// CHECK-NOZUPP: #{{(1|2)}} Thread1
+// CHECK-NOZUPP: SUMMARY: ThreadSanitizer: heap-use-after-free{{.*}}Thread2
+// CHECK-SUPP: ThreadSanitizer: Matched 1 suppressions
+// CHECK-SUPP: 1 race:^Thread2$
diff --git a/test/tsan/free_race.c.supp b/test/tsan/free_race.c.supp
new file mode 100644
index 000000000000..f5d6a4969a41
--- /dev/null
+++ b/test/tsan/free_race.c.supp
@@ -0,0 +1,2 @@
+# Suppression for a use-after-free in free_race.c
+race:^Thread2$
diff --git a/test/tsan/free_race2.c b/test/tsan/free_race2.c
new file mode 100644
index 000000000000..de6b2ae1fcbb
--- /dev/null
+++ b/test/tsan/free_race2.c
@@ -0,0 +1,26 @@
+// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <stdlib.h>
+
+void __attribute__((noinline)) foo(int *mem) {
+ free(mem);
+}
+
+void __attribute__((noinline)) bar(int *mem) {
+ mem[0] = 42;
+}
+
+int main() {
+ int *mem = (int*)malloc(100);
+ foo(mem);
+ bar(mem);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: heap-use-after-free
+// CHECK: Write of size 4 at {{.*}} by main thread:
+// CHECK: #0 bar
+// CHECK: #1 main
+// CHECK: Previous write of size 8 at {{.*}} by main thread:
+// CHECK: #0 free
+// CHECK: #{{1|2}} foo
+// CHECK: #{{2|3}} main
diff --git a/test/tsan/getline_nohang.cc b/test/tsan/getline_nohang.cc
new file mode 100644
index 000000000000..89afbe1a66a8
--- /dev/null
+++ b/test/tsan/getline_nohang.cc
@@ -0,0 +1,39 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t
+
+// Make sure TSan doesn't deadlock on a file stream lock at program shutdown.
+// See https://code.google.com/p/thread-sanitizer/issues/detail?id=47
+#ifdef __FreeBSD__
+#define _WITH_GETLINE // to declare getline()
+#endif
+
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+void *thread(void *unused) {
+ char *line = NULL;
+ size_t size;
+ int fd[2];
+ pipe(fd);
+ // Forge a non-standard stream to make sure it's not closed.
+ FILE *stream = fdopen(fd[0], "r");
+ while (1) {
+ volatile int res = getline(&line, &size, stream);
+ (void)res;
+ }
+ return NULL;
+}
+
+int main() {
+ pthread_t t;
+ pthread_attr_t a;
+ pthread_attr_init(&a);
+ pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED);
+ pthread_create(&t, &a, thread, NULL);
+ pthread_attr_destroy(&a);
+ fprintf(stderr, "DONE\n");
+ return 0;
+ // ThreadSanitizer used to hang here because of a deadlock on a file stream.
+}
+
+// CHECK: DONE
diff --git a/test/tsan/global_race.cc b/test/tsan/global_race.cc
new file mode 100644
index 000000000000..e12bb1d220f8
--- /dev/null
+++ b/test/tsan/global_race.cc
@@ -0,0 +1,28 @@
+// RUN: %clangxx_tsan -O1 %s -o %T/global_race.cc.exe && %deflake %run %T/global_race.cc.exe | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+
+int GlobalData[10];
+
+void *Thread(void *a) {
+ sleep(1);
+ GlobalData[2] = 42;
+ return 0;
+}
+
+int main() {
+ // On FreeBSD, the %p conversion specifier works as 0x%x and thus does not
+ // match to the format used in the diagnotic message.
+ fprintf(stderr, "addr=0x%012lx\n", (unsigned long) GlobalData);
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ GlobalData[2] = 43;
+ pthread_join(t, 0);
+}
+
+// CHECK: addr=[[ADDR:0x[0-9,a-f]+]]
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Location is global 'GlobalData' of size 40 at [[ADDR]] (global_race.cc.exe+0x{{[0-9,a-f]+}})
+
diff --git a/test/tsan/global_race2.cc b/test/tsan/global_race2.cc
new file mode 100644
index 000000000000..ac994cc0f4c4
--- /dev/null
+++ b/test/tsan/global_race2.cc
@@ -0,0 +1,28 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+
+int x;
+
+void *Thread(void *a) {
+ sleep(1);
+ x = 1;
+ return 0;
+}
+
+int main() {
+ // On FreeBSD, the %p conversion specifier works as 0x%x and thus does not
+ // match to the format used in the diagnotic message.
+ fprintf(stderr, "addr2=0x%012lx\n", (unsigned long) &x);
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ x = 0;
+ pthread_join(t, 0);
+}
+
+// CHECK: addr2=[[ADDR2:0x[0-9,a-f]+]]
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Location is global 'x' of size 4 at [[ADDR2]] ({{.*}}+0x{{[0-9,a-f]+}})
+
diff --git a/test/tsan/global_race3.cc b/test/tsan/global_race3.cc
new file mode 100644
index 000000000000..a3222bb3d8cb
--- /dev/null
+++ b/test/tsan/global_race3.cc
@@ -0,0 +1,32 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+
+namespace XXX {
+ struct YYY {
+ static int ZZZ[10];
+ };
+ int YYY::ZZZ[10];
+}
+
+void *Thread(void *a) {
+ sleep(1);
+ XXX::YYY::ZZZ[0] = 1;
+ return 0;
+}
+
+int main() {
+ // On FreeBSD, the %p conversion specifier works as 0x%x and thus does not
+ // match to the format used in the diagnotic message.
+ fprintf(stderr, "addr3=0x%012lx\n", (unsigned long) XXX::YYY::ZZZ);
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ XXX::YYY::ZZZ[0] = 0;
+ pthread_join(t, 0);
+}
+
+// CHECK: addr3=[[ADDR3:0x[0-9,a-f]+]]
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Location is global 'XXX::YYY::ZZZ' of size 40 at [[ADDR3]] ({{.*}}+0x{{[0-9,a-f]+}})
diff --git a/test/tsan/halt_on_error.cc b/test/tsan/halt_on_error.cc
new file mode 100644
index 000000000000..3c55c60a457e
--- /dev/null
+++ b/test/tsan/halt_on_error.cc
@@ -0,0 +1,27 @@
+// RUN: %clang_tsan -O1 %s -o %t && TSAN_OPTIONS="$TSAN_OPTIONS halt_on_error=1" %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int X;
+
+void *Thread(void *x) {
+ sleep(1);
+ X = 42;
+ return 0;
+}
+
+int main() {
+ fprintf(stderr, "BEFORE\n");
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ X = 43;
+ pthread_join(t, 0);
+ fprintf(stderr, "AFTER\n");
+ return 0;
+}
+
+// CHECK: BEFORE
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK-NOT: AFTER
+
diff --git a/test/tsan/heap_race.cc b/test/tsan/heap_race.cc
new file mode 100644
index 000000000000..c3da68f42658
--- /dev/null
+++ b/test/tsan/heap_race.cc
@@ -0,0 +1,20 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stddef.h>
+
+void *Thread(void *a) {
+ ((int*)a)[0]++;
+ return NULL;
+}
+
+int main() {
+ int *p = new int(42);
+ pthread_t t;
+ pthread_create(&t, NULL, Thread, p);
+ p[0]++;
+ pthread_join(t, NULL);
+ delete p;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/ignore_free.cc b/test/tsan/ignore_free.cc
new file mode 100644
index 000000000000..1df6dce2f5e0
--- /dev/null
+++ b/test/tsan/ignore_free.cc
@@ -0,0 +1,35 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+extern "C" {
+void AnnotateIgnoreReadsBegin(const char *f, int l);
+void AnnotateIgnoreReadsEnd(const char *f, int l);
+void AnnotateIgnoreWritesBegin(const char *f, int l);
+void AnnotateIgnoreWritesEnd(const char *f, int l);
+}
+
+void *Thread(void *p) {
+ *(int*)p = 42;
+ return 0;
+}
+
+int main() {
+ int *p = new int(0);
+ pthread_t t;
+ pthread_create(&t, 0, Thread, p);
+ sleep(1);
+ AnnotateIgnoreReadsBegin(__FILE__, __LINE__);
+ AnnotateIgnoreWritesBegin(__FILE__, __LINE__);
+ free(p);
+ AnnotateIgnoreReadsEnd(__FILE__, __LINE__);
+ AnnotateIgnoreWritesEnd(__FILE__, __LINE__);
+ pthread_join(t, 0);
+ fprintf(stderr, "OK\n");
+ return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+// CHECK: OK
diff --git a/test/tsan/ignore_lib0.cc b/test/tsan/ignore_lib0.cc
new file mode 100644
index 000000000000..fe1a35558015
--- /dev/null
+++ b/test/tsan/ignore_lib0.cc
@@ -0,0 +1,30 @@
+// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib0.so
+// RUN: %clangxx_tsan -O1 %s -L%T -lignore_lib0 -o %t
+// RUN: echo running w/o suppressions:
+// RUN: LD_LIBRARY_PATH=%T${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} %deflake %run %t | FileCheck %s --check-prefix=CHECK-NOSUPP
+// RUN: echo running with suppressions:
+// RUN: LD_LIBRARY_PATH=%T${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-WITHSUPP
+
+// Tests that interceptors coming from a library specified in called_from_lib
+// suppression are ignored.
+
+#ifndef LIB
+
+extern "C" void libfunc();
+
+int main() {
+ libfunc();
+}
+
+#else // #ifdef LIB
+
+#include "ignore_lib_lib.h"
+
+#endif // #ifdef LIB
+
+// CHECK-NOSUPP: WARNING: ThreadSanitizer: data race
+// CHECK-NOSUPP: OK
+
+// CHECK-WITHSUPP-NOT: WARNING: ThreadSanitizer: data race
+// CHECK-WITHSUPP: OK
+
diff --git a/test/tsan/ignore_lib0.cc.supp b/test/tsan/ignore_lib0.cc.supp
new file mode 100644
index 000000000000..7728c926b7de
--- /dev/null
+++ b/test/tsan/ignore_lib0.cc.supp
@@ -0,0 +1,2 @@
+called_from_lib:/libignore_lib0.so
+
diff --git a/test/tsan/ignore_lib1.cc b/test/tsan/ignore_lib1.cc
new file mode 100644
index 000000000000..30a9994b94f5
--- /dev/null
+++ b/test/tsan/ignore_lib1.cc
@@ -0,0 +1,42 @@
+// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib1.so
+// RUN: %clangxx_tsan -O1 %s -o %t
+// RUN: echo running w/o suppressions:
+// RUN: %deflake %run %t | FileCheck %s --check-prefix=CHECK-NOSUPP
+// RUN: echo running with suppressions:
+// RUN: TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-WITHSUPP
+
+// Tests that interceptors coming from a dynamically loaded library specified
+// in called_from_lib suppression are ignored.
+
+#ifndef LIB
+
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <libgen.h>
+#include <string>
+
+int main(int argc, char **argv) {
+ std::string lib = std::string(dirname(argv[0])) + "/libignore_lib1.so";
+ void *h = dlopen(lib.c_str(), RTLD_GLOBAL | RTLD_NOW);
+ if (h == 0)
+ exit(printf("failed to load the library (%d)\n", errno));
+ void (*f)() = (void(*)())dlsym(h, "libfunc");
+ if (f == 0)
+ exit(printf("failed to find the func (%d)\n", errno));
+ f();
+}
+
+#else // #ifdef LIB
+
+#include "ignore_lib_lib.h"
+
+#endif // #ifdef LIB
+
+// CHECK-NOSUPP: WARNING: ThreadSanitizer: data race
+// CHECK-NOSUPP: OK
+
+// CHECK-WITHSUPP-NOT: WARNING: ThreadSanitizer: data race
+// CHECK-WITHSUPP: OK
+
diff --git a/test/tsan/ignore_lib1.cc.supp b/test/tsan/ignore_lib1.cc.supp
new file mode 100644
index 000000000000..9f4119ec0bc4
--- /dev/null
+++ b/test/tsan/ignore_lib1.cc.supp
@@ -0,0 +1,2 @@
+called_from_lib:/libignore_lib1.so$
+
diff --git a/test/tsan/ignore_lib2.cc b/test/tsan/ignore_lib2.cc
new file mode 100644
index 000000000000..23a0872feabe
--- /dev/null
+++ b/test/tsan/ignore_lib2.cc
@@ -0,0 +1,33 @@
+// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib2_0.so
+// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib2_1.so
+// RUN: %clangxx_tsan -O1 %s -o %t
+// RUN: TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" %deflake %run %t | FileCheck %s
+
+// Tests that called_from_lib suppression matched against 2 libraries
+// causes program crash (this is not supported).
+
+#ifndef LIB
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <libgen.h>
+#include <string>
+
+int main(int argc, char **argv) {
+ std::string lib0 = std::string(dirname(argv[0])) + "/libignore_lib2_0.so";
+ std::string lib1 = std::string(dirname(argv[0])) + "/libignore_lib2_1.so";
+ dlopen(lib0.c_str(), RTLD_GLOBAL | RTLD_NOW);
+ dlopen(lib1.c_str(), RTLD_GLOBAL | RTLD_NOW);
+ fprintf(stderr, "OK\n");
+}
+
+#else // #ifdef LIB
+
+extern "C" void libfunc() {
+}
+
+#endif // #ifdef LIB
+
+// CHECK: ThreadSanitizer: called_from_lib suppression 'ignore_lib2' is matched against 2 libraries
+// CHECK-NOT: OK
+
diff --git a/test/tsan/ignore_lib2.cc.supp b/test/tsan/ignore_lib2.cc.supp
new file mode 100644
index 000000000000..1419c71c67ef
--- /dev/null
+++ b/test/tsan/ignore_lib2.cc.supp
@@ -0,0 +1,2 @@
+called_from_lib:ignore_lib2
+
diff --git a/test/tsan/ignore_lib3.cc b/test/tsan/ignore_lib3.cc
new file mode 100644
index 000000000000..137109ea6cb4
--- /dev/null
+++ b/test/tsan/ignore_lib3.cc
@@ -0,0 +1,33 @@
+// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib3.so
+// RUN: %clangxx_tsan -O1 %s -o %t
+// RUN: TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" %deflake %run %t | FileCheck %s
+
+// Tests that unloading of a library matched against called_from_lib suppression
+// causes program crash (this is not supported).
+
+#ifndef LIB
+
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <libgen.h>
+#include <string>
+
+int main(int argc, char **argv) {
+ std::string lib = std::string(dirname(argv[0])) + "/libignore_lib3.so";
+ void *h = dlopen(lib.c_str(), RTLD_GLOBAL | RTLD_NOW);
+ dlclose(h);
+ fprintf(stderr, "OK\n");
+}
+
+#else // #ifdef LIB
+
+extern "C" void libfunc() {
+}
+
+#endif // #ifdef LIB
+
+// CHECK: ThreadSanitizer: library {{.*}} that was matched against called_from_lib suppression 'ignore_lib3.so' is unloaded
+// CHECK-NOT: OK
+
diff --git a/test/tsan/ignore_lib3.cc.supp b/test/tsan/ignore_lib3.cc.supp
new file mode 100644
index 000000000000..975dbcef99fe
--- /dev/null
+++ b/test/tsan/ignore_lib3.cc.supp
@@ -0,0 +1,2 @@
+called_from_lib:ignore_lib3.so
+
diff --git a/test/tsan/ignore_lib_lib.h b/test/tsan/ignore_lib_lib.h
new file mode 100644
index 000000000000..2bfe84dfc0ec
--- /dev/null
+++ b/test/tsan/ignore_lib_lib.h
@@ -0,0 +1,25 @@
+#include <pthread.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+void *volatile mem;
+volatile int len;
+
+void *Thread(void *p) {
+ while ((p = __atomic_load_n(&mem, __ATOMIC_ACQUIRE)) == 0)
+ usleep(100);
+ memset(p, 0, len);
+ return 0;
+}
+
+extern "C" void libfunc() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ len = 10;
+ __atomic_store_n(&mem, malloc(len), __ATOMIC_RELEASE);
+ pthread_join(t, 0);
+ free(mem);
+ fprintf(stderr, "OK\n");
+}
diff --git a/test/tsan/ignore_malloc.cc b/test/tsan/ignore_malloc.cc
new file mode 100644
index 000000000000..0f1fb5e3dfdc
--- /dev/null
+++ b/test/tsan/ignore_malloc.cc
@@ -0,0 +1,38 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+extern "C" {
+void AnnotateIgnoreReadsBegin(const char *f, int l);
+void AnnotateIgnoreReadsEnd(const char *f, int l);
+void AnnotateIgnoreWritesBegin(const char *f, int l);
+void AnnotateIgnoreWritesEnd(const char *f, int l);
+}
+
+int *g;
+
+void *Thread(void *a) {
+ int *p = 0;
+ while ((p = __atomic_load_n(&g, __ATOMIC_RELAXED)) == 0)
+ usleep(100);
+ *p = 42;
+ return 0;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ AnnotateIgnoreWritesBegin(__FILE__, __LINE__);
+ int *p = new int(0);
+ AnnotateIgnoreWritesEnd(__FILE__, __LINE__);
+ __atomic_store_n(&g, p, __ATOMIC_RELAXED);
+ pthread_join(t, 0);
+ delete p;
+ fprintf(stderr, "OK\n");
+ return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+// CHECK: OK
diff --git a/test/tsan/ignore_race.cc b/test/tsan/ignore_race.cc
new file mode 100644
index 000000000000..c6e067fabec0
--- /dev/null
+++ b/test/tsan/ignore_race.cc
@@ -0,0 +1,31 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+
+extern "C" void AnnotateIgnoreWritesBegin(const char *f, int l);
+extern "C" void AnnotateIgnoreWritesEnd(const char *f, int l);
+extern "C" void AnnotateIgnoreReadsBegin(const char *f, int l);
+extern "C" void AnnotateIgnoreReadsEnd(const char *f, int l);
+
+void *Thread(void *x) {
+ AnnotateIgnoreWritesBegin(__FILE__, __LINE__);
+ AnnotateIgnoreReadsBegin(__FILE__, __LINE__);
+ Global = 42;
+ AnnotateIgnoreReadsEnd(__FILE__, __LINE__);
+ AnnotateIgnoreWritesEnd(__FILE__, __LINE__);
+ return 0;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ sleep(1);
+ Global = 43;
+ pthread_join(t, 0);
+ printf("OK\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/ignore_sync.cc b/test/tsan/ignore_sync.cc
new file mode 100644
index 000000000000..ae24a8c49e75
--- /dev/null
+++ b/test/tsan/ignore_sync.cc
@@ -0,0 +1,30 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+
+extern "C" void AnnotateIgnoreSyncBegin(const char*, int);
+extern "C" void AnnotateIgnoreSyncEnd(const char*, int);
+
+int Global;
+pthread_mutex_t Mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void *Thread(void *x) {
+ AnnotateIgnoreSyncBegin(0, 0);
+ pthread_mutex_lock(&Mutex);
+ Global++;
+ pthread_mutex_unlock(&Mutex);
+ AnnotateIgnoreSyncEnd(0, 0);
+ return 0;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ pthread_mutex_lock(&Mutex);
+ Global++;
+ pthread_mutex_unlock(&Mutex);
+ pthread_join(t, 0);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+
diff --git a/test/tsan/inlined_memcpy_race.cc b/test/tsan/inlined_memcpy_race.cc
new file mode 100644
index 000000000000..a95576a83c9a
--- /dev/null
+++ b/test/tsan/inlined_memcpy_race.cc
@@ -0,0 +1,38 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int x[4], z[4];
+
+void *MemCpyThread(void *a) {
+ memcpy((int*)a, z, 16);
+ return NULL;
+}
+
+void *MemSetThread(void *a) {
+ sleep(1);
+ memset((int*)a, 0, 16);
+ return NULL;
+}
+
+int main() {
+ pthread_t t[2];
+ // Race on x between memcpy and memset
+ pthread_create(&t[0], NULL, MemCpyThread, x);
+ pthread_create(&t[1], NULL, MemSetThread, x);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ printf("PASS\n");
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: #0 memset
+// CHECK: #1 MemSetThread
+// CHECK: Previous write
+// CHECK: #0 memcpy
+// CHECK: #1 MemCpyThread
+
diff --git a/test/tsan/inlined_memcpy_race2.cc b/test/tsan/inlined_memcpy_race2.cc
new file mode 100644
index 000000000000..63b560f02269
--- /dev/null
+++ b/test/tsan/inlined_memcpy_race2.cc
@@ -0,0 +1,38 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int y[4], z[4];
+
+void *MemMoveThread(void *a) {
+ memmove((int*)a, z, 16);
+ return NULL;
+}
+
+void *MemSetThread(void *a) {
+ sleep(1);
+ memset((int*)a, 0, 16);
+ return NULL;
+}
+
+int main() {
+ pthread_t t[2];
+ // Race on y between memmove and memset
+ pthread_create(&t[0], NULL, MemMoveThread, y);
+ pthread_create(&t[1], NULL, MemSetThread, y);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+
+ printf("PASS\n");
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: #0 memset
+// CHECK: #1 MemSetThread
+// CHECK: Previous write
+// CHECK: #0 memmove
+// CHECK: #1 MemMoveThread
diff --git a/test/tsan/interface_atomic_test.c b/test/tsan/interface_atomic_test.c
new file mode 100644
index 000000000000..18d860ea02e2
--- /dev/null
+++ b/test/tsan/interface_atomic_test.c
@@ -0,0 +1,16 @@
+// Test that we can include header with TSan atomic interface.
+// RUN: %clang_tsan %s -o %t && %run %t | FileCheck %s
+#include <sanitizer/tsan_interface_atomic.h>
+#include <stdio.h>
+
+int main() {
+ __tsan_atomic32 a;
+ __tsan_atomic32_store(&a, 100, __tsan_memory_order_release);
+ int res = __tsan_atomic32_load(&a, __tsan_memory_order_acquire);
+ if (res == 100) {
+ // CHECK: PASS
+ printf("PASS\n");
+ return 0;
+ }
+ return 1;
+}
diff --git a/test/tsan/java.h b/test/tsan/java.h
new file mode 100644
index 000000000000..d986d08be060
--- /dev/null
+++ b/test/tsan/java.h
@@ -0,0 +1,21 @@
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+extern "C" {
+typedef unsigned long jptr; // NOLINT
+void __tsan_java_preinit(const char *libjvm_path);
+void __tsan_java_init(jptr heap_begin, jptr heap_size);
+int __tsan_java_fini();
+void __tsan_java_alloc(jptr ptr, jptr size);
+void __tsan_java_free(jptr ptr, jptr size);
+void __tsan_java_move(jptr src, jptr dst, jptr size);
+void __tsan_java_finalize();
+void __tsan_java_mutex_lock(jptr addr);
+void __tsan_java_mutex_unlock(jptr addr);
+void __tsan_java_mutex_read_lock(jptr addr);
+void __tsan_java_mutex_read_unlock(jptr addr);
+void __tsan_java_mutex_lock_rec(jptr addr, int rec);
+int __tsan_java_mutex_unlock_rec(jptr addr);
+}
diff --git a/test/tsan/java_alloc.cc b/test/tsan/java_alloc.cc
new file mode 100644
index 000000000000..4a606f7940d3
--- /dev/null
+++ b/test/tsan/java_alloc.cc
@@ -0,0 +1,38 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include "java.h"
+
+int const kHeapSize = 1024 * 1024;
+
+void stress(jptr addr) {
+ for (jptr sz = 8; sz <= 32; sz <<= 1) {
+ for (jptr i = 0; i < kHeapSize / 4 / sz; i++) {
+ __tsan_java_alloc(addr + i * sz, sz);
+ }
+ __tsan_java_move(addr, addr + kHeapSize / 2, kHeapSize / 4);
+ __tsan_java_free(addr + kHeapSize / 2, kHeapSize / 4);
+ }
+}
+
+void *Thread(void *p) {
+ stress((jptr)p);
+ return 0;
+}
+
+int main() {
+ jptr jheap = (jptr)malloc(kHeapSize + 8) + 8;
+ __tsan_java_init(jheap, kHeapSize);
+ pthread_t th;
+ pthread_create(&th, 0, Thread, (void*)(jheap + kHeapSize / 4));
+ stress(jheap);
+ pthread_join(th, 0);
+ if (__tsan_java_fini() != 0) {
+ printf("FAILED\n");
+ return 1;
+ }
+ printf("DONE\n");
+ return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+// CHECK-NOT: FAILED
+// CHECK: DONE
diff --git a/test/tsan/java_finalizer.cc b/test/tsan/java_finalizer.cc
new file mode 100644
index 000000000000..d5c6a22d1e16
--- /dev/null
+++ b/test/tsan/java_finalizer.cc
@@ -0,0 +1,27 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include "java.h"
+
+void *Thread(void *p) {
+ sleep(1);
+ __tsan_java_finalize();
+ *(int*)p = 42;
+ return 0;
+}
+
+int main() {
+ int const kHeapSize = 1024 * 1024;
+ jptr jheap = (jptr)malloc(kHeapSize + 8) + 8;
+ __tsan_java_init(jheap, kHeapSize);
+ const int kBlockSize = 16;
+ __tsan_java_alloc(jheap, kBlockSize);
+ pthread_t th;
+ pthread_create(&th, 0, Thread, (void*)jheap);
+ *(int*)jheap = 43;
+ pthread_join(th, 0);
+ __tsan_java_free(jheap, kBlockSize);
+ fprintf(stderr, "DONE\n");
+ return __tsan_java_fini();
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+// CHECK: DONE
diff --git a/test/tsan/java_lock.cc b/test/tsan/java_lock.cc
new file mode 100644
index 000000000000..36a0f8b7bff3
--- /dev/null
+++ b/test/tsan/java_lock.cc
@@ -0,0 +1,36 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include "java.h"
+#include <unistd.h>
+
+jptr varaddr;
+jptr lockaddr;
+
+void *Thread(void *p) {
+ sleep(1);
+ __tsan_java_mutex_lock(lockaddr);
+ *(int*)varaddr = 42;
+ __tsan_java_mutex_unlock(lockaddr);
+ return 0;
+}
+
+int main() {
+ int const kHeapSize = 1024 * 1024;
+ jptr jheap = (jptr)malloc(kHeapSize + 8) + 8;
+ __tsan_java_init(jheap, kHeapSize);
+ const int kBlockSize = 16;
+ __tsan_java_alloc(jheap, kBlockSize);
+ varaddr = jheap;
+ lockaddr = jheap + 8;
+ pthread_t th;
+ pthread_create(&th, 0, Thread, 0);
+ __tsan_java_mutex_lock(lockaddr);
+ *(int*)varaddr = 43;
+ __tsan_java_mutex_unlock(lockaddr);
+ pthread_join(th, 0);
+ __tsan_java_free(jheap, kBlockSize);
+ fprintf(stderr, "DONE\n");
+ return __tsan_java_fini();
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+// CHECK: DONE
diff --git a/test/tsan/java_lock_move.cc b/test/tsan/java_lock_move.cc
new file mode 100644
index 000000000000..19c3e35d6633
--- /dev/null
+++ b/test/tsan/java_lock_move.cc
@@ -0,0 +1,41 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include "java.h"
+
+jptr varaddr;
+jptr lockaddr;
+jptr varaddr2;
+jptr lockaddr2;
+
+void *Thread(void *p) {
+ sleep(1);
+ __tsan_java_mutex_lock(lockaddr2);
+ *(int*)varaddr2 = 42;
+ __tsan_java_mutex_unlock(lockaddr2);
+ return 0;
+}
+
+int main() {
+ int const kHeapSize = 1024 * 1024;
+ jptr jheap = (jptr)malloc(kHeapSize + 8) + 8;
+ __tsan_java_init(jheap, kHeapSize);
+ const int kBlockSize = 64;
+ int const kMove = 1024;
+ __tsan_java_alloc(jheap, kBlockSize);
+ varaddr = jheap;
+ lockaddr = jheap + 46;
+ varaddr2 = varaddr + kMove;
+ lockaddr2 = lockaddr + kMove;
+ pthread_t th;
+ pthread_create(&th, 0, Thread, 0);
+ __tsan_java_mutex_lock(lockaddr);
+ *(int*)varaddr = 43;
+ __tsan_java_mutex_unlock(lockaddr);
+ __tsan_java_move(varaddr, varaddr2, kBlockSize);
+ pthread_join(th, 0);
+ __tsan_java_free(varaddr2, kBlockSize);
+ printf("DONE\n");
+ return __tsan_java_fini();
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+// CHECK: DONE
diff --git a/test/tsan/java_lock_rec.cc b/test/tsan/java_lock_rec.cc
new file mode 100644
index 000000000000..2b0ab0eb92d0
--- /dev/null
+++ b/test/tsan/java_lock_rec.cc
@@ -0,0 +1,55 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include "java.h"
+#include <unistd.h>
+
+jptr varaddr;
+jptr lockaddr;
+
+void *Thread(void *p) {
+ __tsan_java_mutex_lock(lockaddr);
+ __tsan_java_mutex_lock(lockaddr);
+ *(int*)varaddr = 42;
+ int rec = __tsan_java_mutex_unlock_rec(lockaddr);
+ if (rec != 2) {
+ printf("FAILED 0 rec=%d\n", rec);
+ exit(1);
+ }
+ sleep(2);
+ __tsan_java_mutex_lock_rec(lockaddr, rec);
+ if (*(int*)varaddr != 43) {
+ printf("FAILED 3 var=%d\n", *(int*)varaddr);
+ exit(1);
+ }
+ __tsan_java_mutex_unlock(lockaddr);
+ __tsan_java_mutex_unlock(lockaddr);
+ return 0;
+}
+
+int main() {
+ int const kHeapSize = 1024 * 1024;
+ jptr jheap = (jptr)malloc(kHeapSize + 8) + 8;
+ __tsan_java_init(jheap, kHeapSize);
+ const int kBlockSize = 16;
+ __tsan_java_alloc(jheap, kBlockSize);
+ varaddr = jheap;
+ *(int*)varaddr = 0;
+ lockaddr = jheap + 8;
+ pthread_t th;
+ pthread_create(&th, 0, Thread, 0);
+ sleep(1);
+ __tsan_java_mutex_lock(lockaddr);
+ if (*(int*)varaddr != 42) {
+ printf("FAILED 1 var=%d\n", *(int*)varaddr);
+ exit(1);
+ }
+ *(int*)varaddr = 43;
+ __tsan_java_mutex_unlock(lockaddr);
+ pthread_join(th, 0);
+ __tsan_java_free(jheap, kBlockSize);
+ printf("DONE\n");
+ return __tsan_java_fini();
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+// CHECK-NOT: FAILED
+// CHECK: DONE
diff --git a/test/tsan/java_lock_rec_race.cc b/test/tsan/java_lock_rec_race.cc
new file mode 100644
index 000000000000..841aa396360d
--- /dev/null
+++ b/test/tsan/java_lock_rec_race.cc
@@ -0,0 +1,49 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include "java.h"
+#include <unistd.h>
+
+jptr varaddr;
+jptr lockaddr;
+
+void *Thread(void *p) {
+ __tsan_java_mutex_lock(lockaddr);
+ __tsan_java_mutex_lock(lockaddr);
+ __tsan_java_mutex_lock(lockaddr);
+ int rec = __tsan_java_mutex_unlock_rec(lockaddr);
+ if (rec != 3) {
+ printf("FAILED 0 rec=%d\n", rec);
+ exit(1);
+ }
+ *(int*)varaddr = 42;
+ sleep(2);
+ __tsan_java_mutex_lock_rec(lockaddr, rec);
+ __tsan_java_mutex_unlock(lockaddr);
+ __tsan_java_mutex_unlock(lockaddr);
+ __tsan_java_mutex_unlock(lockaddr);
+ return 0;
+}
+
+int main() {
+ int const kHeapSize = 1024 * 1024;
+ jptr jheap = (jptr)malloc(kHeapSize + 8) + 8;
+ __tsan_java_init(jheap, kHeapSize);
+ const int kBlockSize = 16;
+ __tsan_java_alloc(jheap, kBlockSize);
+ varaddr = jheap;
+ *(int*)varaddr = 0;
+ lockaddr = jheap + 8;
+ pthread_t th;
+ pthread_create(&th, 0, Thread, 0);
+ sleep(1);
+ __tsan_java_mutex_lock(lockaddr);
+ *(int*)varaddr = 43;
+ __tsan_java_mutex_unlock(lockaddr);
+ pthread_join(th, 0);
+ __tsan_java_free(jheap, kBlockSize);
+ printf("DONE\n");
+ return __tsan_java_fini();
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK-NOT: FAILED
+// CHECK: DONE
diff --git a/test/tsan/java_move_overlap.cc b/test/tsan/java_move_overlap.cc
new file mode 100644
index 000000000000..12955b4ba0de
--- /dev/null
+++ b/test/tsan/java_move_overlap.cc
@@ -0,0 +1,72 @@
+// RUN: %clangxx_tsan -O1 %s -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+// RUN: %run %t arg 2>&1 | FileCheck %s
+#include "java.h"
+
+jptr varaddr1_old;
+jptr varaddr2_old;
+jptr lockaddr1_old;
+jptr lockaddr2_old;
+jptr varaddr1_new;
+jptr varaddr2_new;
+jptr lockaddr1_new;
+jptr lockaddr2_new;
+
+void *Thread(void *p) {
+ sleep(1);
+ __tsan_java_mutex_lock(lockaddr1_new);
+ *(char*)varaddr1_new = 43;
+ __tsan_java_mutex_unlock(lockaddr1_new);
+ __tsan_java_mutex_lock(lockaddr2_new);
+ *(char*)varaddr2_new = 43;
+ __tsan_java_mutex_unlock(lockaddr2_new);
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ int const kHeapSize = 1024 * 1024;
+ void *jheap = malloc(kHeapSize);
+ jheap = (char*)jheap + 8;
+ __tsan_java_init((jptr)jheap, kHeapSize);
+ const int kBlockSize = 64;
+ int const kMove = 32;
+ varaddr1_old = (jptr)jheap;
+ lockaddr1_old = (jptr)jheap + 1;
+ varaddr2_old = (jptr)jheap + kBlockSize - 1;
+ lockaddr2_old = (jptr)jheap + kBlockSize - 16;
+ varaddr1_new = varaddr1_old + kMove;
+ lockaddr1_new = lockaddr1_old + kMove;
+ varaddr2_new = varaddr2_old + kMove;
+ lockaddr2_new = lockaddr2_old + kMove;
+ if (argc > 1) {
+ // Move memory backwards.
+ varaddr1_old += kMove;
+ lockaddr1_old += kMove;
+ varaddr2_old += kMove;
+ lockaddr2_old += kMove;
+ varaddr1_new -= kMove;
+ lockaddr1_new -= kMove;
+ varaddr2_new -= kMove;
+ lockaddr2_new -= kMove;
+ }
+ __tsan_java_alloc(varaddr1_old, kBlockSize);
+
+ pthread_t th;
+ pthread_create(&th, 0, Thread, 0);
+
+ __tsan_java_mutex_lock(lockaddr1_old);
+ *(char*)varaddr1_old = 43;
+ __tsan_java_mutex_unlock(lockaddr1_old);
+ __tsan_java_mutex_lock(lockaddr2_old);
+ *(char*)varaddr2_old = 43;
+ __tsan_java_mutex_unlock(lockaddr2_old);
+
+ __tsan_java_move(varaddr1_old, varaddr1_new, kBlockSize);
+ pthread_join(th, 0);
+ __tsan_java_free(varaddr1_new, kBlockSize);
+ printf("DONE\n");
+ return __tsan_java_fini();
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+// CHECK: DONE
diff --git a/test/tsan/java_move_overlap_race.cc b/test/tsan/java_move_overlap_race.cc
new file mode 100644
index 000000000000..2b3769be6117
--- /dev/null
+++ b/test/tsan/java_move_overlap_race.cc
@@ -0,0 +1,53 @@
+// RUN: %clangxx_tsan -O1 %s -o %t
+// RUN: %deflake %run %t | FileCheck %s
+// RUN: %deflake %run %t arg | FileCheck %s
+#include "java.h"
+
+jptr varaddr1_old;
+jptr varaddr2_old;
+jptr varaddr1_new;
+jptr varaddr2_new;
+
+void *Thread(void *p) {
+ sleep(1);
+ *(int*)varaddr1_new = 43;
+ *(int*)varaddr2_new = 43;
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ int const kHeapSize = 1024 * 1024;
+ void *jheap = malloc(kHeapSize);
+ jheap = (char*)jheap + 8;
+ __tsan_java_init((jptr)jheap, kHeapSize);
+ const int kBlockSize = 64;
+ int const kMove = 32;
+ varaddr1_old = (jptr)jheap;
+ varaddr2_old = (jptr)jheap + kBlockSize - 1;
+ varaddr1_new = varaddr1_old + kMove;
+ varaddr2_new = varaddr2_old + kMove;
+ if (argc > 1) {
+ // Move memory backwards.
+ varaddr1_old += kMove;
+ varaddr2_old += kMove;
+ varaddr1_new -= kMove;
+ varaddr2_new -= kMove;
+ }
+ __tsan_java_alloc(varaddr1_old, kBlockSize);
+
+ pthread_t th;
+ pthread_create(&th, 0, Thread, 0);
+
+ *(int*)varaddr1_old = 43;
+ *(int*)varaddr2_old = 43;
+
+ __tsan_java_move(varaddr1_old, varaddr1_new, kBlockSize);
+ pthread_join(th, 0);
+ __tsan_java_free(varaddr1_new, kBlockSize);
+ printf("DONE\n");
+ return __tsan_java_fini();
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: DONE
diff --git a/test/tsan/java_race.cc b/test/tsan/java_race.cc
new file mode 100644
index 000000000000..ede058e85d8a
--- /dev/null
+++ b/test/tsan/java_race.cc
@@ -0,0 +1,25 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include "java.h"
+
+void *Thread(void *p) {
+ *(int*)p = 42;
+ return 0;
+}
+
+int main() {
+ int const kHeapSize = 1024 * 1024;
+ jptr jheap = (jptr)malloc(kHeapSize + 8) + 8;
+ __tsan_java_init(jheap, kHeapSize);
+ const int kBlockSize = 16;
+ __tsan_java_alloc(jheap, kBlockSize);
+ pthread_t th;
+ pthread_create(&th, 0, Thread, (void*)jheap);
+ *(int*)jheap = 43;
+ pthread_join(th, 0);
+ __tsan_java_free(jheap, kBlockSize);
+ fprintf(stderr, "DONE\n");
+ return __tsan_java_fini();
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: DONE
diff --git a/test/tsan/java_race_move.cc b/test/tsan/java_race_move.cc
new file mode 100644
index 000000000000..8a51be92aa10
--- /dev/null
+++ b/test/tsan/java_race_move.cc
@@ -0,0 +1,33 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include "java.h"
+
+jptr varaddr;
+jptr varaddr2;
+
+void *Thread(void *p) {
+ sleep(1);
+ *(int*)varaddr2 = 42;
+ return 0;
+}
+
+int main() {
+ int const kHeapSize = 1024 * 1024;
+ jptr jheap = (jptr)malloc(kHeapSize + 8) + 8;
+ __tsan_java_init(jheap, kHeapSize);
+ const int kBlockSize = 64;
+ int const kMove = 1024;
+ __tsan_java_alloc(jheap, kBlockSize);
+ varaddr = jheap + 16;
+ varaddr2 = varaddr + kMove;
+ pthread_t th;
+ pthread_create(&th, 0, Thread, 0);
+ *(int*)varaddr = 43;
+ __tsan_java_move(varaddr, varaddr2, kBlockSize);
+ pthread_join(th, 0);
+ __tsan_java_free(varaddr2, kBlockSize);
+ fprintf(stderr, "DONE\n");
+ return __tsan_java_fini();
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: DONE
diff --git a/test/tsan/java_rwlock.cc b/test/tsan/java_rwlock.cc
new file mode 100644
index 000000000000..b03afa6e092d
--- /dev/null
+++ b/test/tsan/java_rwlock.cc
@@ -0,0 +1,36 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include "java.h"
+#include <unistd.h>
+
+jptr varaddr;
+jptr lockaddr;
+
+void *Thread(void *p) {
+ sleep(1);
+ __tsan_java_mutex_read_lock(lockaddr);
+ *(int*)varaddr = 42;
+ __tsan_java_mutex_read_unlock(lockaddr);
+ return 0;
+}
+
+int main() {
+ int const kHeapSize = 1024 * 1024;
+ jptr jheap = (jptr)malloc(kHeapSize + 8) + 8;
+ __tsan_java_init(jheap, kHeapSize);
+ const int kBlockSize = 16;
+ __tsan_java_alloc(jheap, kBlockSize);
+ varaddr = jheap;
+ lockaddr = jheap + 8;
+ pthread_t th;
+ pthread_create(&th, 0, Thread, 0);
+ __tsan_java_mutex_lock(lockaddr);
+ *(int*)varaddr = 43;
+ __tsan_java_mutex_unlock(lockaddr);
+ pthread_join(th, 0);
+ __tsan_java_free(jheap, kBlockSize);
+ printf("DONE\n");
+ return __tsan_java_fini();
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+// CHECK: DONE
diff --git a/test/tsan/libcxx/lit.local.cfg b/test/tsan/libcxx/lit.local.cfg
new file mode 100644
index 000000000000..202b44ee116d
--- /dev/null
+++ b/test/tsan/libcxx/lit.local.cfg
@@ -0,0 +1,10 @@
+def getRoot(config):
+ if not config.parent:
+ return config
+ return getRoot(config.parent)
+
+root = getRoot(config)
+
+if not root.has_libcxx:
+ config.unsupported = True
+
diff --git a/test/tsan/libcxx/std_shared_ptr.cc b/test/tsan/libcxx/std_shared_ptr.cc
new file mode 100644
index 000000000000..191a17cc798d
--- /dev/null
+++ b/test/tsan/libcxx/std_shared_ptr.cc
@@ -0,0 +1,24 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <stdio.h>
+#include <memory>
+#include <thread>
+
+int main() {
+ int v1 = 0;
+ int v2 = 0;
+ std::thread t1;
+ std::thread t2;
+
+ {
+ auto thingy = std::make_shared<int>(42);
+ t1 = std::thread([thingy, &v1] { v1 = *thingy; });
+ t2 = std::thread([thingy, &v2] { v2 = *thingy; });
+ }
+
+ t1.join();
+ t2.join();
+ printf("%d %d\n", v1, v2);
+ // CHECK-NOT: ThreadSanitizer: data race
+ // CHECK: 42 42
+ return 0;
+}
diff --git a/test/tsan/lit.cfg b/test/tsan/lit.cfg
new file mode 100644
index 000000000000..d27500f8e3ea
--- /dev/null
+++ b/test/tsan/lit.cfg
@@ -0,0 +1,65 @@
+# -*- Python -*-
+
+import os
+
+def get_required_attr(config, attr_name):
+ attr_value = getattr(config, attr_name, None)
+ if not attr_value:
+ lit_config.fatal(
+ "No attribute %r in test configuration! You may need to run "
+ "tests from your build directory or add this attribute "
+ "to lit.site.cfg " % attr_name)
+ return attr_value
+
+# Setup config name.
+config.name = 'ThreadSanitizer'
+
+# Setup source root.
+config.test_source_root = os.path.dirname(__file__)
+
+# Setup environment variables for running ThreadSanitizer.
+tsan_options = "atexit_sleep_ms=0"
+
+config.environment['TSAN_OPTIONS'] = tsan_options
+
+# GCC driver doesn't add necessary compile/link flags with -fsanitize=thread.
+if config.compiler_id == 'GNU':
+ extra_cflags = ["-fPIE", "-pthread", "-ldl", "-lstdc++", "-lrt", "-pie"]
+else:
+ extra_cflags = []
+
+# Setup default compiler flags used with -fsanitize=thread option.
+clang_tsan_cflags = ["-fsanitize=thread",
+ "-Wall",
+ "-m64"] + config.debug_info_flags + extra_cflags
+clang_tsan_cxxflags = config.cxx_mode_flags + clang_tsan_cflags
+# Add additional flags if we're using instrumented libc++.
+if config.has_libcxx:
+ # FIXME: Dehardcode this path somehow.
+ libcxx_path = os.path.join(config.compiler_rt_obj_root, "lib",
+ "tsan", "libcxx_tsan")
+ 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",
+ "-I%s" % libcxx_incdir,
+ libcxx_so,
+ "-Wl,-rpath=%s" % libcxx_libdir]
+
+def build_invocation(compile_flags):
+ return " " + " ".join([config.clang] + compile_flags) + " "
+
+config.substitutions.append( ("%clang_tsan ", build_invocation(clang_tsan_cflags)) )
+config.substitutions.append( ("%clangxx_tsan ", build_invocation(clang_tsan_cxxflags)) )
+
+# Define CHECK-%os to check for OS-dependent output.
+config.substitutions.append( ('CHECK-%os', ("CHECK-" + config.host_os)))
+
+config.substitutions.append( ("%deflake ", os.path.join(os.path.dirname(__file__), "deflake.bash")) )
+
+# Default test suffixes.
+config.suffixes = ['.c', '.cc', '.cpp']
+
+# ThreadSanitizer tests are currently supported on FreeBSD and Linux only.
+if config.host_os not in ['FreeBSD', 'Linux']:
+ config.unsupported = True
diff --git a/test/tsan/lit.site.cfg.in b/test/tsan/lit.site.cfg.in
new file mode 100644
index 000000000000..5190b211177d
--- /dev/null
+++ b/test/tsan/lit.site.cfg.in
@@ -0,0 +1,10 @@
+## Autogenerated by LLVM/Clang configuration.
+# Do not edit!
+
+config.has_libcxx = @TSAN_HAS_LIBCXX@
+
+# 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, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg")
diff --git a/test/tsan/load_shared_lib.cc b/test/tsan/load_shared_lib.cc
new file mode 100644
index 000000000000..a27dc1cc6ffb
--- /dev/null
+++ b/test/tsan/load_shared_lib.cc
@@ -0,0 +1,66 @@
+// Check that if the list of shared libraries changes between the two race
+// reports, the second report occurring in a new shared library is still
+// symbolized correctly.
+
+// RUN: %clangxx_tsan -O1 %s -DBUILD_SO -fPIC -shared -o %t-so.so
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+
+#ifdef BUILD_SO
+
+#include <stddef.h>
+#include <unistd.h>
+
+int GLOB_SHARED = 0;
+
+extern "C"
+void *write_from_so(void *unused) {
+ if (unused)
+ sleep(1);
+ GLOB_SHARED++;
+ return NULL;
+}
+
+#else // BUILD_SO
+
+#include <dlfcn.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+
+#include <string>
+
+int GLOB = 0;
+
+void *write_glob(void *unused) {
+ if (unused)
+ sleep(1);
+ GLOB++;
+ return NULL;
+}
+
+void race_two_threads(void *(*access_callback)(void *unused)) {
+ pthread_t t1, t2;
+ pthread_create(&t1, NULL, access_callback, (void*)1);
+ pthread_create(&t2, NULL, access_callback, NULL);
+ pthread_join(t1, NULL);
+ pthread_join(t2, NULL);
+}
+
+int main(int argc, char *argv[]) {
+ std::string path = std::string(argv[0]) + std::string("-so.so");
+ race_two_threads(write_glob);
+ // CHECK: write_glob
+ void *lib = dlopen(path.c_str(), RTLD_NOW);
+ if (!lib) {
+ printf("error in dlopen(): %s\n", dlerror());
+ return 1;
+ }
+ void *(*write_from_so)(void *unused);
+ *(void **)&write_from_so = dlsym(lib, "write_from_so");
+ race_two_threads(write_from_so);
+ // CHECK: write_from_so
+ return 0;
+}
+
+#endif // BUILD_SO
diff --git a/test/tsan/longjmp.cc b/test/tsan/longjmp.cc
new file mode 100644
index 000000000000..d7371c5e4069
--- /dev/null
+++ b/test/tsan/longjmp.cc
@@ -0,0 +1,22 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+
+int foo(jmp_buf env) {
+ longjmp(env, 42);
+}
+
+int main() {
+ jmp_buf env;
+ if (setjmp(env) == 42) {
+ printf("JUMPED\n");
+ return 0;
+ }
+ foo(env);
+ printf("FAILED\n");
+ return 0;
+}
+
+// CHECK-NOT: FAILED
+// CHECK: JUMPED
diff --git a/test/tsan/longjmp2.cc b/test/tsan/longjmp2.cc
new file mode 100644
index 000000000000..546019b2d11a
--- /dev/null
+++ b/test/tsan/longjmp2.cc
@@ -0,0 +1,24 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+
+int foo(sigjmp_buf env) {
+ printf("env=%p\n", env);
+ siglongjmp(env, 42);
+}
+
+int main() {
+ sigjmp_buf env;
+ printf("env=%p\n", env);
+ if (sigsetjmp(env, 1) == 42) {
+ printf("JUMPED\n");
+ return 0;
+ }
+ foo(env);
+ printf("FAILED\n");
+ return 0;
+}
+
+// CHECK-NOT: FAILED
+// CHECK: JUMPED
diff --git a/test/tsan/longjmp3.cc b/test/tsan/longjmp3.cc
new file mode 100644
index 000000000000..71d964dbbed9
--- /dev/null
+++ b/test/tsan/longjmp3.cc
@@ -0,0 +1,48 @@
+// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+
+void bar(jmp_buf env) {
+ volatile int x = 42;
+ longjmp(env, 42);
+ x++;
+}
+
+void foo(jmp_buf env) {
+ volatile int x = 42;
+ bar(env);
+ x++;
+}
+
+void badguy() {
+ pthread_mutex_t mtx;
+ pthread_mutex_init(&mtx, 0);
+ pthread_mutex_lock(&mtx);
+ pthread_mutex_destroy(&mtx);
+}
+
+void mymain() {
+ jmp_buf env;
+ if (setjmp(env) == 42) {
+ badguy();
+ return;
+ }
+ foo(env);
+ printf("FAILED\n");
+}
+
+int main() {
+ volatile int x = 42;
+ mymain();
+ return x;
+}
+
+// CHECK-NOT: FAILED
+// CHECK: WARNING: ThreadSanitizer: destroy of a locked mutex
+// CHECK: #0 pthread_mutex_destroy
+// CHECK: #1 badguy
+// CHECK: #2 mymain
+// CHECK: #3 main
+
diff --git a/test/tsan/longjmp4.cc b/test/tsan/longjmp4.cc
new file mode 100644
index 000000000000..15330f5d83c8
--- /dev/null
+++ b/test/tsan/longjmp4.cc
@@ -0,0 +1,51 @@
+// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include <string.h>
+
+void bar(jmp_buf env) {
+ volatile int x = 42;
+ jmp_buf env2;
+ memcpy(env2, env, sizeof(jmp_buf));
+ longjmp(env2, 42);
+ x++;
+}
+
+void foo(jmp_buf env) {
+ volatile int x = 42;
+ bar(env);
+ x++;
+}
+
+void badguy() {
+ pthread_mutex_t mtx;
+ pthread_mutex_init(&mtx, 0);
+ pthread_mutex_lock(&mtx);
+ pthread_mutex_destroy(&mtx);
+}
+
+void mymain() {
+ jmp_buf env;
+ if (setjmp(env) == 42) {
+ badguy();
+ return;
+ }
+ foo(env);
+ printf("FAILED\n");
+}
+
+int main() {
+ volatile int x = 42;
+ mymain();
+ return x;
+}
+
+// CHECK-NOT: FAILED
+// CHECK: WARNING: ThreadSanitizer: destroy of a locked mutex
+// CHECK: #0 pthread_mutex_destroy
+// CHECK: #1 badguy
+// CHECK: #2 mymain
+// CHECK: #3 main
+
diff --git a/test/tsan/malloc_overflow.cc b/test/tsan/malloc_overflow.cc
new file mode 100644
index 000000000000..dadc94484f01
--- /dev/null
+++ b/test/tsan/malloc_overflow.cc
@@ -0,0 +1,23 @@
+// RUN: %clangxx_tsan -O1 %s -o %t
+// RUN: TSAN_OPTIONS=allocator_may_return_null=1 %run %t 2>&1 | FileCheck %s
+#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+ void *p = malloc((size_t)-1);
+ if (p != 0)
+ printf("FAIL malloc(-1) = %p\n", p);
+ p = malloc((size_t)-1 / 2);
+ if (p != 0)
+ printf("FAIL malloc(-1/2) = %p\n", p);
+ p = calloc((size_t)-1, (size_t)-1);
+ if (p != 0)
+ printf("FAIL calloc(-1, -1) = %p\n", p);
+ p = calloc((size_t)-1 / 2, (size_t)-1 / 2);
+ if (p != 0)
+ printf("FAIL calloc(-1/2, -1/2) = %p\n", p);
+ printf("OK\n");
+}
+
+// CHECK-NOT: FAIL
+// CHECK-NOT: failed to allocate
diff --git a/test/tsan/malloc_stack.cc b/test/tsan/malloc_stack.cc
new file mode 100644
index 000000000000..6027360754aa
--- /dev/null
+++ b/test/tsan/malloc_stack.cc
@@ -0,0 +1,25 @@
+// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <unistd.h>
+
+_Atomic(int*) p;
+
+void *thr(void *a) {
+ sleep(1);
+ int *pp = __c11_atomic_load(&p, __ATOMIC_RELAXED);
+ *pp = 42;
+ return 0;
+}
+
+int main() {
+ pthread_t th;
+ pthread_create(&th, 0, thr, p);
+ __c11_atomic_store(&p, new int, __ATOMIC_RELAXED);
+ pthread_join(th, 0);
+}
+
+// CHECK: data race
+// CHECK: Previous write
+// CHECK: #0 operator new
+// CHECK: Location is heap block
+// CHECK: #0 operator new
diff --git a/test/tsan/map32bit.cc b/test/tsan/map32bit.cc
new file mode 100644
index 000000000000..3a76fa2f6d62
--- /dev/null
+++ b/test/tsan/map32bit.cc
@@ -0,0 +1,41 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/mman.h>
+
+// Test for issue:
+// https://code.google.com/p/thread-sanitizer/issues/detail?id=5
+
+void *Thread(void *ptr) {
+ *(int*)ptr = 42;
+ return 0;
+}
+
+int main() {
+ void *ptr = mmap(0, 128 << 10, PROT_READ|PROT_WRITE,
+ MAP_32BIT|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+ fprintf(stderr, "ptr=%p\n", ptr);
+ if (ptr == MAP_FAILED) {
+ fprintf(stderr, "mmap failed: %d\n", errno);
+ return 1;
+ }
+ if ((uintptr_t)ptr >= (1ull << 32)) {
+ fprintf(stderr, "ptr is too high\n");
+ return 1;
+ }
+ pthread_t t;
+ pthread_create(&t, 0, Thread, ptr);
+ sleep(1);
+ *(int*)ptr = 42;
+ pthread_join(t, 0);
+ munmap(ptr, 128 << 10);
+ fprintf(stderr, "DONE\n");
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: DONE
+
diff --git a/test/tsan/memcpy_race.cc b/test/tsan/memcpy_race.cc
new file mode 100644
index 000000000000..8ec8e0a3e6a5
--- /dev/null
+++ b/test/tsan/memcpy_race.cc
@@ -0,0 +1,42 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+char *data = new char[10];
+char *data1 = new char[10];
+char *data2 = new char[10];
+
+void *Thread1(void *x) {
+ static volatile int size = 1;
+ memcpy(data+5, data1, size);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ static volatile int size = 4;
+ sleep(1);
+ memcpy(data+3, data2, size);
+ return NULL;
+}
+
+int main() {
+ fprintf(stderr, "addr=%p\n", &data[5]);
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ return 0;
+}
+
+// CHECK: addr=[[ADDR:0x[0-9,a-f]+]]
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Write of size 1 at [[ADDR]] by thread T2:
+// CHECK: #0 memcpy
+// CHECK: #1 Thread2
+// CHECK: Previous write of size 1 at [[ADDR]] by thread T1:
+// CHECK: #0 memcpy
+// CHECK: #1 Thread1
diff --git a/test/tsan/mmap_large.cc b/test/tsan/mmap_large.cc
new file mode 100644
index 000000000000..e715ea666231
--- /dev/null
+++ b/test/tsan/mmap_large.cc
@@ -0,0 +1,20 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <stdint.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/mman.h>
+
+int main() {
+ const size_t kLog2Size = 39;
+ const uintptr_t kLocation = 0x40ULL << kLog2Size;
+ void *p = mmap(
+ reinterpret_cast<void*>(kLocation),
+ 1ULL << kLog2Size,
+ PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE,
+ -1, 0);
+ fprintf(stderr, "DONE %p %d\n", p, errno);
+ return p == MAP_FAILED;
+}
+
+// CHECK: DONE
diff --git a/test/tsan/mop_with_offset.cc b/test/tsan/mop_with_offset.cc
new file mode 100644
index 000000000000..e44c78b7d1b4
--- /dev/null
+++ b/test/tsan/mop_with_offset.cc
@@ -0,0 +1,36 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <unistd.h>
+
+void *Thread1(void *x) {
+ int *p = (int*)x;
+ p[0] = 1;
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ sleep(1);
+ char *p = (char*)x;
+ p[2] = 1;
+ return NULL;
+}
+
+int main() {
+ int *data = new int(42);
+ fprintf(stderr, "ptr1=%p\n", data);
+ fprintf(stderr, "ptr2=%p\n", (char*)data + 2);
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, data);
+ pthread_create(&t[1], NULL, Thread2, data);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ delete data;
+}
+
+// CHECK: ptr1=[[PTR1:0x[0-9,a-f]+]]
+// CHECK: ptr2=[[PTR2:0x[0-9,a-f]+]]
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Write of size 1 at [[PTR2]] by thread T2:
+// CHECK: Previous write of size 4 at [[PTR1]] by thread T1:
diff --git a/test/tsan/mop_with_offset2.cc b/test/tsan/mop_with_offset2.cc
new file mode 100644
index 000000000000..a465d5f09471
--- /dev/null
+++ b/test/tsan/mop_with_offset2.cc
@@ -0,0 +1,36 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <unistd.h>
+
+void *Thread1(void *x) {
+ sleep(1);
+ int *p = (int*)x;
+ p[0] = 1;
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ char *p = (char*)x;
+ p[2] = 1;
+ return NULL;
+}
+
+int main() {
+ int *data = new int(42);
+ fprintf(stderr, "ptr1=%p\n", data);
+ fprintf(stderr, "ptr2=%p\n", (char*)data + 2);
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, data);
+ pthread_create(&t[1], NULL, Thread2, data);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ delete data;
+}
+
+// CHECK: ptr1=[[PTR1:0x[0-9,a-f]+]]
+// CHECK: ptr2=[[PTR2:0x[0-9,a-f]+]]
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Write of size 4 at [[PTR1]] by thread T1:
+// CHECK: Previous write of size 1 at [[PTR2]] by thread T2:
diff --git a/test/tsan/must_deadlock.cc b/test/tsan/must_deadlock.cc
new file mode 100644
index 000000000000..1409800e9b39
--- /dev/null
+++ b/test/tsan/must_deadlock.cc
@@ -0,0 +1,50 @@
+// Test that the deadlock detector can find a deadlock that actually happened.
+// Currently we will fail to report such a deadlock because we check for
+// cycles in lock-order graph after pthread_mutex_lock.
+
+// RUN: %clangxx_tsan %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// XFAIL: *
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+pthread_mutex_t mu1, mu2;
+pthread_barrier_t barrier;
+
+void *Thread(void *p) {
+ // mu2 => mu1
+ pthread_mutex_lock(&mu2);
+ pthread_barrier_wait(&barrier);
+ pthread_mutex_lock(&mu1);
+ // CHECK: ThreadSanitizer: lock-order-inversion (potential deadlock)
+ pthread_mutex_unlock(&mu1);
+ pthread_mutex_unlock(&mu2);
+ return p;
+}
+
+int main() {
+ pthread_mutex_init(&mu1, NULL);
+ pthread_mutex_init(&mu2, NULL);
+ pthread_barrier_init(&barrier, 0, 2);
+
+ fprintf(stderr, "This test is going to deadlock and die in 3 seconds\n");
+ alarm(3);
+
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+
+ // mu1 => mu2
+ pthread_mutex_lock(&mu1);
+ pthread_barrier_wait(&barrier);
+ pthread_mutex_lock(&mu2);
+ pthread_mutex_unlock(&mu2);
+ pthread_mutex_unlock(&mu1);
+
+ pthread_join(t, 0);
+
+ pthread_mutex_destroy(&mu1);
+ pthread_mutex_destroy(&mu2);
+ pthread_barrier_destroy(&barrier);
+ fprintf(stderr, "FAILED\n");
+}
diff --git a/test/tsan/mutex_bad_read_lock.cc b/test/tsan/mutex_bad_read_lock.cc
new file mode 100644
index 000000000000..84a2976d53e4
--- /dev/null
+++ b/test/tsan/mutex_bad_read_lock.cc
@@ -0,0 +1,19 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+extern "C" void AnnotateRWLockAcquired(const char *f, int l, void *m, long rw);
+
+int main() {
+ int m = 0;
+ AnnotateRWLockAcquired(__FILE__, __LINE__, &m, 1);
+ AnnotateRWLockAcquired(__FILE__, __LINE__, &m, 0);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: read lock of a write locked mutex
+// CHECK: #0 AnnotateRWLockAcquired
+// CHECK: #1 main
+// CHECK: Location is stack of main thread.
+// CHECK: Mutex {{.*}}) created at:
+// CHECK: #0 AnnotateRWLockAcquired
+// CHECK: #1 main
+// CHECK: SUMMARY: ThreadSanitizer: read lock of a write locked mutex
+
diff --git a/test/tsan/mutex_bad_read_unlock.cc b/test/tsan/mutex_bad_read_unlock.cc
new file mode 100644
index 000000000000..dcee51599d55
--- /dev/null
+++ b/test/tsan/mutex_bad_read_unlock.cc
@@ -0,0 +1,20 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+extern "C" void AnnotateRWLockAcquired(const char *f, int l, void *m, long rw);
+extern "C" void AnnotateRWLockReleased(const char *f, int l, void *m, long rw);
+
+int main() {
+ int m = 0;
+ AnnotateRWLockAcquired(__FILE__, __LINE__, &m, 1);
+ AnnotateRWLockReleased(__FILE__, __LINE__, &m, 0);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: read unlock of a write locked mutex
+// CHECK: #0 AnnotateRWLockReleased
+// CHECK: #1 main
+// CHECK: Location is stack of main thread.
+// CHECK: Mutex {{.*}}) created at:
+// CHECK: #0 AnnotateRWLockAcquired
+// CHECK: #1 main
+// CHECK: SUMMARY: ThreadSanitizer: read unlock of a write locked mutex
+
diff --git a/test/tsan/mutex_bad_unlock.cc b/test/tsan/mutex_bad_unlock.cc
new file mode 100644
index 000000000000..6b483cf17eda
--- /dev/null
+++ b/test/tsan/mutex_bad_unlock.cc
@@ -0,0 +1,18 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+extern "C" void AnnotateRWLockReleased(const char *f, int l, void *m, long rw);
+
+int main() {
+ int m = 0;
+ AnnotateRWLockReleased(__FILE__, __LINE__, &m, 1);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: unlock of an unlocked mutex (or by a wrong thread)
+// CHECK: #0 AnnotateRWLockReleased
+// CHECK: #1 main
+// CHECK: Location is stack of main thread.
+// CHECK: Mutex {{.*}} created at:
+// CHECK: #0 AnnotateRWLockReleased
+// CHECK: #1 main
+// CHECK: SUMMARY: ThreadSanitizer: unlock of an unlocked mutex (or by a wrong thread)
+
diff --git a/test/tsan/mutex_cycle2.c b/test/tsan/mutex_cycle2.c
new file mode 100644
index 000000000000..031830d5ec63
--- /dev/null
+++ b/test/tsan/mutex_cycle2.c
@@ -0,0 +1,35 @@
+// RUN: %clangxx_tsan %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: TSAN_OPTIONS=detect_deadlocks=1 not %run %t 2>&1 | FileCheck %s
+// RUN: TSAN_OPTIONS=detect_deadlocks=0 %run %t 2>&1 | FileCheck %s --check-prefix=DISABLED
+// RUN: echo "deadlock:main" > %t.sup
+// RUN: TSAN_OPTIONS="suppressions=%t.sup" %run %t 2>&1 | FileCheck %s --check-prefix=DISABLED
+// RUN: echo "deadlock:zzzz" > %t.sup
+// RUN: TSAN_OPTIONS="suppressions=%t.sup" not %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+
+int main() {
+ pthread_mutex_t mu1, mu2;
+ pthread_mutex_init(&mu1, NULL);
+ pthread_mutex_init(&mu2, NULL);
+
+ // mu1 => mu2
+ pthread_mutex_lock(&mu1);
+ pthread_mutex_lock(&mu2);
+ pthread_mutex_unlock(&mu2);
+ pthread_mutex_unlock(&mu1);
+
+ // mu2 => mu1
+ pthread_mutex_lock(&mu2);
+ pthread_mutex_lock(&mu1);
+ // CHECK: ThreadSanitizer: lock-order-inversion (potential deadlock)
+ // DISABLED-NOT: ThreadSanitizer
+ // DISABLED: PASS
+ pthread_mutex_unlock(&mu1);
+ pthread_mutex_unlock(&mu2);
+
+ pthread_mutex_destroy(&mu1);
+ pthread_mutex_destroy(&mu2);
+ fprintf(stderr, "PASS\n");
+}
diff --git a/test/tsan/mutex_destroy_locked.cc b/test/tsan/mutex_destroy_locked.cc
new file mode 100644
index 000000000000..b81905ec68fd
--- /dev/null
+++ b/test/tsan/mutex_destroy_locked.cc
@@ -0,0 +1,22 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <unistd.h>
+
+int main() {
+ pthread_mutex_t m;
+ pthread_mutex_init(&m, 0);
+ pthread_mutex_lock(&m);
+ pthread_mutex_destroy(&m);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: destroy of a locked mutex
+// CHECK: #0 pthread_mutex_destroy
+// CHECK: #1 main
+// CHECK: and:
+// CHECK: #0 pthread_mutex_lock
+// CHECK: #1 main
+// CHECK: Mutex {{.*}} created at:
+// CHECK: #0 pthread_mutex_init
+// CHECK: #1 main
+// CHECK: SUMMARY: ThreadSanitizer: destroy of a locked mutex{{.*}}main
diff --git a/test/tsan/mutex_double_lock.cc b/test/tsan/mutex_double_lock.cc
new file mode 100644
index 000000000000..c1bebf73706e
--- /dev/null
+++ b/test/tsan/mutex_double_lock.cc
@@ -0,0 +1,29 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <unistd.h>
+
+extern "C" void AnnotateRWLockAcquired(const char *f, int l, void *m, long rw);
+
+void *ThreadFunc(void *m) {
+ AnnotateRWLockAcquired(__FILE__, __LINE__, m, 1);
+ return 0;
+}
+
+int main() {
+ int m = 0;
+ AnnotateRWLockAcquired(__FILE__, __LINE__, &m, 1);
+ pthread_t th;
+ pthread_create(&th, 0, ThreadFunc, &m);
+ pthread_join(th, 0);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: double lock of a mutex
+// CHECK: #0 AnnotateRWLockAcquired
+// CHECK: #1 ThreadFunc
+// CHECK: Location is stack of main thread.
+// CHECK: Mutex {{.*}} created at:
+// CHECK: #0 AnnotateRWLockAcquired
+// CHECK: #1 main
+// CHECK: SUMMARY: ThreadSanitizer: double lock of a mutex {{.*}}mutex_double_lock.cc{{.*}}ThreadFunc
+
diff --git a/test/tsan/mutexset1.cc b/test/tsan/mutexset1.cc
new file mode 100644
index 000000000000..72964edfb1e7
--- /dev/null
+++ b/test/tsan/mutexset1.cc
@@ -0,0 +1,37 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+pthread_mutex_t mtx;
+
+void *Thread1(void *x) {
+ sleep(1);
+ pthread_mutex_lock(&mtx);
+ Global++;
+ pthread_mutex_unlock(&mtx);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ Global--;
+ return NULL;
+}
+
+int main() {
+ // CHECK: WARNING: ThreadSanitizer: data race
+ // CHECK: Write of size 4 at {{.*}} by thread T1
+ // CHECK: (mutexes: write [[M1:M[0-9]+]]):
+ // CHECK: Previous write of size 4 at {{.*}} by thread T2:
+ // CHECK: Mutex [[M1]] (0x{{.*}}) created at:
+ // CHECK: #0 pthread_mutex_init
+ // CHECK: #1 main {{.*}}/mutexset1.cc:[[@LINE+1]]
+ pthread_mutex_init(&mtx, 0);
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ pthread_mutex_destroy(&mtx);
+}
diff --git a/test/tsan/mutexset2.cc b/test/tsan/mutexset2.cc
new file mode 100644
index 000000000000..01a5f5df6e94
--- /dev/null
+++ b/test/tsan/mutexset2.cc
@@ -0,0 +1,37 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+pthread_mutex_t mtx;
+
+void *Thread1(void *x) {
+ pthread_mutex_lock(&mtx);
+ Global++;
+ pthread_mutex_unlock(&mtx);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ sleep(1);
+ Global--;
+ return NULL;
+}
+
+int main() {
+ // CHECK: WARNING: ThreadSanitizer: data race
+ // CHECK: Write of size 4 at {{.*}} by thread T2:
+ // CHECK: Previous write of size 4 at {{.*}} by thread T1
+ // CHECK: (mutexes: write [[M1:M[0-9]+]]):
+ // CHECK: Mutex [[M1]] (0x{{.*}}) created at:
+ // CHECK: #0 pthread_mutex_init
+ // CHECK: #1 main {{.*}}/mutexset2.cc:[[@LINE+1]]
+ pthread_mutex_init(&mtx, 0);
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ pthread_mutex_destroy(&mtx);
+}
diff --git a/test/tsan/mutexset3.cc b/test/tsan/mutexset3.cc
new file mode 100644
index 000000000000..e14bb1111e32
--- /dev/null
+++ b/test/tsan/mutexset3.cc
@@ -0,0 +1,45 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+pthread_mutex_t mtx1;
+pthread_mutex_t mtx2;
+
+void *Thread1(void *x) {
+ sleep(1);
+ pthread_mutex_lock(&mtx1);
+ pthread_mutex_lock(&mtx2);
+ Global++;
+ pthread_mutex_unlock(&mtx2);
+ pthread_mutex_unlock(&mtx1);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ Global--;
+ return NULL;
+}
+
+int main() {
+ // CHECK: WARNING: ThreadSanitizer: data race
+ // CHECK: Write of size 4 at {{.*}} by thread T1
+ // CHECK: (mutexes: write [[M1:M[0-9]+]], write [[M2:M[0-9]+]]):
+ // CHECK: Previous write of size 4 at {{.*}} by thread T2:
+ // CHECK: Mutex [[M1]] (0x{{.*}}) created at:
+ // CHECK: #0 pthread_mutex_init
+ // CHECK: #1 main {{.*}}/mutexset3.cc:[[@LINE+4]]
+ // CHECK: Mutex [[M2]] (0x{{.*}}) created at:
+ // CHECK: #0 pthread_mutex_init
+ // CHECK: #1 main {{.*}}/mutexset3.cc:[[@LINE+2]]
+ pthread_mutex_init(&mtx1, 0);
+ pthread_mutex_init(&mtx2, 0);
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ pthread_mutex_destroy(&mtx1);
+ pthread_mutex_destroy(&mtx2);
+}
diff --git a/test/tsan/mutexset4.cc b/test/tsan/mutexset4.cc
new file mode 100644
index 000000000000..db860e005d67
--- /dev/null
+++ b/test/tsan/mutexset4.cc
@@ -0,0 +1,45 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+pthread_mutex_t mtx1;
+pthread_mutex_t mtx2;
+
+void *Thread1(void *x) {
+ pthread_mutex_lock(&mtx1);
+ pthread_mutex_lock(&mtx2);
+ Global++;
+ pthread_mutex_unlock(&mtx2);
+ pthread_mutex_unlock(&mtx1);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ sleep(1);
+ Global--;
+ return NULL;
+}
+
+int main() {
+ // CHECK: WARNING: ThreadSanitizer: data race
+ // CHECK: Write of size 4 at {{.*}} by thread T2:
+ // CHECK: Previous write of size 4 at {{.*}} by thread T1
+ // CHECK: (mutexes: write [[M1:M[0-9]+]], write [[M2:M[0-9]+]]):
+ // CHECK: Mutex [[M1]] (0x{{.*}}) created at:
+ // CHECK: #0 pthread_mutex_init
+ // CHECK: #1 main {{.*}}/mutexset4.cc:[[@LINE+4]]
+ // CHECK: Mutex [[M2]] (0x{{.*}}) created at:
+ // CHECK: #0 pthread_mutex_init
+ // CHECK: #1 main {{.*}}/mutexset4.cc:[[@LINE+2]]
+ pthread_mutex_init(&mtx1, 0);
+ pthread_mutex_init(&mtx2, 0);
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ pthread_mutex_destroy(&mtx1);
+ pthread_mutex_destroy(&mtx2);
+}
diff --git a/test/tsan/mutexset5.cc b/test/tsan/mutexset5.cc
new file mode 100644
index 000000000000..e1cc2fcacf62
--- /dev/null
+++ b/test/tsan/mutexset5.cc
@@ -0,0 +1,46 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+pthread_mutex_t mtx1;
+pthread_mutex_t mtx2;
+
+void *Thread1(void *x) {
+ sleep(1);
+ pthread_mutex_lock(&mtx1);
+ Global++;
+ pthread_mutex_unlock(&mtx1);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ pthread_mutex_lock(&mtx2);
+ Global--;
+ pthread_mutex_unlock(&mtx2);
+ return NULL;
+}
+
+int main() {
+ // CHECK: WARNING: ThreadSanitizer: data race
+ // CHECK: Write of size 4 at {{.*}} by thread T1
+ // CHECK: (mutexes: write [[M1:M[0-9]+]]):
+ // CHECK: Previous write of size 4 at {{.*}} by thread T2
+ // CHECK: (mutexes: write [[M2:M[0-9]+]]):
+ // CHECK: Mutex [[M1]] (0x{{.*}}) created at:
+ // CHECK: #0 pthread_mutex_init
+ // CHECK: #1 main {{.*}}/mutexset5.cc:[[@LINE+4]]
+ // CHECK: Mutex [[M2]] (0x{{.*}}) created at:
+ // CHECK: #0 pthread_mutex_init
+ // CHECK: #1 main {{.*}}/mutexset5.cc:[[@LINE+5]]
+ pthread_mutex_init(&mtx1, 0);
+ pthread_mutex_init(&mtx2, 0);
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ pthread_mutex_destroy(&mtx1);
+ pthread_mutex_destroy(&mtx2);
+}
diff --git a/test/tsan/mutexset6.cc b/test/tsan/mutexset6.cc
new file mode 100644
index 000000000000..07dcc0a7394d
--- /dev/null
+++ b/test/tsan/mutexset6.cc
@@ -0,0 +1,53 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+pthread_mutex_t mtx1;
+pthread_spinlock_t mtx2;
+pthread_rwlock_t mtx3;
+
+void *Thread1(void *x) {
+ sleep(1);
+ pthread_mutex_lock(&mtx1);
+ Global++;
+ pthread_mutex_unlock(&mtx1);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ pthread_mutex_lock(&mtx1);
+ pthread_mutex_unlock(&mtx1);
+ pthread_spin_lock(&mtx2);
+ pthread_rwlock_rdlock(&mtx3);
+ Global--;
+ pthread_spin_unlock(&mtx2);
+ pthread_rwlock_unlock(&mtx3);
+ return NULL;
+}
+
+int main() {
+ // CHECK: WARNING: ThreadSanitizer: data race
+ // CHECK: Write of size 4 at {{.*}} by thread T1
+ // CHECK: (mutexes: write [[M1:M[0-9]+]]):
+ // CHECK: Previous write of size 4 at {{.*}} by thread T2
+ // CHECK: (mutexes: write [[M2:M[0-9]+]], read [[M3:M[0-9]+]]):
+ // CHECK: Mutex [[M1]] (0x{{.*}}) created at:
+ // CHECK: #1 main {{.*}}/mutexset6.cc:[[@LINE+5]]
+ // CHECK: Mutex [[M2]] (0x{{.*}}) created at:
+ // CHECK: #1 main {{.*}}/mutexset6.cc:[[@LINE+4]]
+ // CHECK: Mutex [[M3]] (0x{{.*}}) created at:
+ // CHECK: #1 main {{.*}}/mutexset6.cc:[[@LINE+3]]
+ pthread_mutex_init(&mtx1, 0);
+ pthread_spin_init(&mtx2, 0);
+ pthread_rwlock_init(&mtx3, 0);
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ pthread_mutex_destroy(&mtx1);
+ pthread_spin_destroy(&mtx2);
+ pthread_rwlock_destroy(&mtx3);
+}
diff --git a/test/tsan/mutexset7.cc b/test/tsan/mutexset7.cc
new file mode 100644
index 000000000000..12174844c799
--- /dev/null
+++ b/test/tsan/mutexset7.cc
@@ -0,0 +1,40 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+__thread int huge[1024*1024];
+
+void *Thread1(void *x) {
+ sleep(1);
+ Global++;
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ pthread_mutex_t *mtx = new pthread_mutex_t;
+ pthread_mutex_init(mtx, 0);
+ pthread_mutex_lock(mtx);
+ Global--;
+ pthread_mutex_unlock(mtx);
+ pthread_mutex_destroy(mtx);
+ delete mtx;
+ return NULL;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Write of size 4 at {{.*}} by thread T1:
+// CHECK: Previous write of size 4 at {{.*}} by thread T2
+// CHECK: (mutexes: write [[M1:M[0-9]+]]):
+// CHECK: Mutex [[M1]] is already destroyed
+// CHECK-NOT: Mutex {{.*}} created at
+
diff --git a/test/tsan/mutexset8.cc b/test/tsan/mutexset8.cc
new file mode 100644
index 000000000000..3e1ab8c5a744
--- /dev/null
+++ b/test/tsan/mutexset8.cc
@@ -0,0 +1,39 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+pthread_mutex_t *mtx;
+
+void *Thread1(void *x) {
+ sleep(1);
+ pthread_mutex_lock(mtx);
+ Global++;
+ pthread_mutex_unlock(mtx);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ Global--;
+ return NULL;
+}
+
+int main() {
+ // CHECK: WARNING: ThreadSanitizer: data race
+ // CHECK: Write of size 4 at {{.*}} by thread T1
+ // CHECK: (mutexes: write [[M1:M[0-9]+]]):
+ // CHECK: Previous write of size 4 at {{.*}} by thread T2:
+ // CHECK: Mutex [[M1]] (0x{{.*}}) created at:
+ // CHECK: #0 pthread_mutex_init
+ // CHECK: #1 main {{.*}}/mutexset8.cc
+ mtx = new pthread_mutex_t;
+ pthread_mutex_init(mtx, 0);
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ pthread_mutex_destroy(mtx);
+ delete mtx;
+}
diff --git a/test/tsan/printf-1.c b/test/tsan/printf-1.c
new file mode 100644
index 000000000000..9116c956e30e
--- /dev/null
+++ b/test/tsan/printf-1.c
@@ -0,0 +1,16 @@
+// RUN: %clang_tsan -O2 %s -o %t
+// RUN: ASAN_OPTIONS=check_printf=1 %run %t 2>&1 | FileCheck %s
+// RUN: ASAN_OPTIONS=check_printf=0 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+int main() {
+ volatile char c = '0';
+ volatile int x = 12;
+ volatile float f = 1.239;
+ volatile char s[] = "34";
+ printf("%c %d %.3f %s\n", c, x, f, s);
+ return 0;
+ // Check that printf works fine under Tsan.
+ // CHECK: 0 12 1.239 34
+}
diff --git a/test/tsan/process_sleep.h b/test/tsan/process_sleep.h
new file mode 100644
index 000000000000..5938a42bf8b2
--- /dev/null
+++ b/test/tsan/process_sleep.h
@@ -0,0 +1,7 @@
+#include <time.h>
+
+static void process_sleep(int sec) {
+ clock_t beg = clock();
+ while((clock() - beg) / CLOCKS_PER_SEC < sec)
+ usleep(100);
+}
diff --git a/test/tsan/pthread_atfork_deadlock.c b/test/tsan/pthread_atfork_deadlock.c
new file mode 100644
index 000000000000..0f33b9022e5f
--- /dev/null
+++ b/test/tsan/pthread_atfork_deadlock.c
@@ -0,0 +1,33 @@
+// RUN: %clang_tsan -O1 %s -lpthread -o %t && %deflake %run %t | FileCheck %s
+// Regression test for
+// https://code.google.com/p/thread-sanitizer/issues/detail?id=61
+// When the data race was reported, pthread_atfork() handler used to be
+// executed which caused another race report in the same thread, which resulted
+// in a deadlock.
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int glob = 0;
+
+void *worker(void *unused) {
+ sleep(1);
+ glob++;
+ return NULL;
+}
+
+void atfork() {
+ fprintf(stderr, "ATFORK\n");
+ glob++;
+}
+
+int main() {
+ pthread_atfork(atfork, NULL, NULL);
+ pthread_t t;
+ pthread_create(&t, NULL, worker, NULL);
+ glob++;
+ pthread_join(t, NULL);
+ // CHECK: ThreadSanitizer: data race
+ // CHECK-NOT: ATFORK
+ return 0;
+}
diff --git a/test/tsan/race_on_barrier.c b/test/tsan/race_on_barrier.c
new file mode 100644
index 000000000000..99b18fe4d8e6
--- /dev/null
+++ b/test/tsan/race_on_barrier.c
@@ -0,0 +1,31 @@
+// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+
+pthread_barrier_t B;
+int Global;
+
+void *Thread1(void *x) {
+ pthread_barrier_init(&B, 0, 2);
+ pthread_barrier_wait(&B);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ sleep(1);
+ pthread_barrier_wait(&B);
+ return NULL;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, NULL, Thread1, NULL);
+ Thread2(0);
+ pthread_join(t, NULL);
+ pthread_barrier_destroy(&B);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/race_on_barrier2.c b/test/tsan/race_on_barrier2.c
new file mode 100644
index 000000000000..98c028e19fdd
--- /dev/null
+++ b/test/tsan/race_on_barrier2.c
@@ -0,0 +1,31 @@
+// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+
+pthread_barrier_t B;
+int Global;
+
+void *Thread1(void *x) {
+ if (pthread_barrier_wait(&B) == PTHREAD_BARRIER_SERIAL_THREAD)
+ pthread_barrier_destroy(&B);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ if (pthread_barrier_wait(&B) == PTHREAD_BARRIER_SERIAL_THREAD)
+ pthread_barrier_destroy(&B);
+ return NULL;
+}
+
+int main() {
+ pthread_barrier_init(&B, 0, 2);
+ pthread_t t;
+ pthread_create(&t, NULL, Thread1, NULL);
+ Thread2(0);
+ pthread_join(t, NULL);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/race_on_heap.cc b/test/tsan/race_on_heap.cc
new file mode 100644
index 000000000000..a66e0c4f93f7
--- /dev/null
+++ b/test/tsan/race_on_heap.cc
@@ -0,0 +1,47 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+void *Thread1(void *p) {
+ *(int*)p = 42;
+ return 0;
+}
+
+void *Thread2(void *p) {
+ *(int*)p = 44;
+ return 0;
+}
+
+void *alloc() {
+ return malloc(99);
+}
+
+void *AllocThread(void* arg) {
+ return alloc();
+}
+
+int main() {
+ void *p = 0;
+ pthread_t t[2];
+ pthread_create(&t[0], 0, AllocThread, 0);
+ pthread_join(t[0], &p);
+ fprintf(stderr, "addr=%p\n", p);
+ pthread_create(&t[0], 0, Thread1, (char*)p + 16);
+ pthread_create(&t[1], 0, Thread2, (char*)p + 16);
+ pthread_join(t[0], 0);
+ pthread_join(t[1], 0);
+ return 0;
+}
+
+// CHECK: addr=[[ADDR:0x[0-9,a-f]+]]
+// CHECK: WARNING: ThreadSanitizer: data race
+// ...
+// CHECK: Location is heap block of size 99 at [[ADDR]] allocated by thread T1:
+// CHCEK: #0 malloc
+// CHECK: #{{1|2}} alloc
+// CHECK: #{{2|3}} AllocThread
+// ...
+// CHECK: Thread T1 (tid={{.*}}, finished) created by main thread at:
+// CHECK: #0 pthread_create
+// CHECK: #1 main
diff --git a/test/tsan/race_on_mutex.c b/test/tsan/race_on_mutex.c
new file mode 100644
index 000000000000..b4adeeb4df72
--- /dev/null
+++ b/test/tsan/race_on_mutex.c
@@ -0,0 +1,42 @@
+// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+
+pthread_mutex_t Mtx;
+int Global;
+
+void *Thread1(void *x) {
+ pthread_mutex_init(&Mtx, 0);
+ pthread_mutex_lock(&Mtx);
+ Global = 42;
+ pthread_mutex_unlock(&Mtx);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ sleep(1);
+ pthread_mutex_lock(&Mtx);
+ Global = 43;
+ pthread_mutex_unlock(&Mtx);
+ return NULL;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ pthread_mutex_destroy(&Mtx);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK-NEXT: Atomic read of size 1 at {{.*}} by thread T2:
+// CHECK-NEXT: #0 pthread_mutex_lock
+// CHECK-NEXT: #1 Thread2{{.*}} {{.*}}race_on_mutex.c:20{{(:3)?}} ({{.*}})
+// CHECK: Previous write of size 1 at {{.*}} by thread T1:
+// CHECK-NEXT: #0 pthread_mutex_init {{.*}} ({{.*}})
+// CHECK-NEXT: #1 Thread1{{.*}} {{.*}}race_on_mutex.c:11{{(:3)?}} ({{.*}})
diff --git a/test/tsan/race_on_mutex2.c b/test/tsan/race_on_mutex2.c
new file mode 100644
index 000000000000..1796d0c6480b
--- /dev/null
+++ b/test/tsan/race_on_mutex2.c
@@ -0,0 +1,24 @@
+// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+
+void *Thread(void *x) {
+ pthread_mutex_lock((pthread_mutex_t*)x);
+ pthread_mutex_unlock((pthread_mutex_t*)x);
+ return 0;
+}
+
+int main() {
+ pthread_mutex_t Mtx;
+ pthread_mutex_init(&Mtx, 0);
+ pthread_t t;
+ pthread_create(&t, 0, Thread, &Mtx);
+ sleep(1);
+ pthread_mutex_destroy(&Mtx);
+ pthread_join(t, 0);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/race_on_puts.cc b/test/tsan/race_on_puts.cc
new file mode 100644
index 000000000000..1f2b4db836ed
--- /dev/null
+++ b/test/tsan/race_on_puts.cc
@@ -0,0 +1,29 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+char s[] = "abracadabra";
+
+void *Thread0(void *p) {
+ puts(s);
+ return 0;
+}
+
+void *Thread1(void *p) {
+ s[3] = 'z';
+ return 0;
+}
+
+int main() {
+ pthread_t th[2];
+ pthread_create(&th[0], 0, Thread0, 0);
+ pthread_create(&th[1], 0, Thread1, 0);
+ pthread_join(th[0], 0);
+ pthread_join(th[1], 0);
+ fprintf(stderr, "DONE");
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: DONE
+
diff --git a/test/tsan/race_on_read.cc b/test/tsan/race_on_read.cc
new file mode 100644
index 000000000000..1ec0522b9035
--- /dev/null
+++ b/test/tsan/race_on_read.cc
@@ -0,0 +1,41 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+int fd;
+char buf;
+
+void *Thread(void *x) {
+ sleep(1);
+ read(fd, &buf, 1);
+ return NULL;
+}
+
+int main() {
+ fd = open("/dev/random", O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "failed to open /dev/random (%d)\n", errno);
+ return 1;
+ }
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread, NULL);
+ pthread_create(&t[1], NULL, Thread, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ close(fd);
+ fprintf(stderr, "DONE\n");
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Write of size 1
+// CHECK: #0 read
+// CHECK: Previous write of size 1
+// CHECK: #0 read
+// CHECK: DONE
+
diff --git a/test/tsan/race_on_speculative_load.cc b/test/tsan/race_on_speculative_load.cc
new file mode 100644
index 000000000000..f816db9e8853
--- /dev/null
+++ b/test/tsan/race_on_speculative_load.cc
@@ -0,0 +1,27 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t | FileCheck %s
+// Regtest for https://code.google.com/p/thread-sanitizer/issues/detail?id=40
+// This is a correct program and tsan should not report a race.
+#include <pthread.h>
+#include <unistd.h>
+#include <stdio.h>
+int g;
+__attribute__((noinline))
+int foo(int cond) {
+ if (cond)
+ return g;
+ return 0;
+}
+void *Thread1(void *p) {
+ long res = foo((long)p);
+ sleep(1);
+ return (void*) res;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread1, 0);
+ g = 1;
+ pthread_join(t, 0);
+ printf("PASS\n");
+ // CHECK: PASS
+}
diff --git a/test/tsan/race_on_write.cc b/test/tsan/race_on_write.cc
new file mode 100644
index 000000000000..484bbb7ae022
--- /dev/null
+++ b/test/tsan/race_on_write.cc
@@ -0,0 +1,39 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+int fd;
+char buf;
+
+void *Thread1(void *x) {
+ buf = 1;
+ sleep(1);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ write(fd, &buf, 1);
+ return NULL;
+}
+
+int main() {
+ fd = open("/dev/null", O_WRONLY);
+ if (fd < 0) return 1;
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ sleep(1);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ close(fd);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Read of size 1
+// CHECK: #0 write
+// CHECK: Previous write of size 1
+// CHECK: #0 Thread1
diff --git a/test/tsan/race_with_finished_thread.cc b/test/tsan/race_with_finished_thread.cc
new file mode 100644
index 000000000000..d28760093c42
--- /dev/null
+++ b/test/tsan/race_with_finished_thread.cc
@@ -0,0 +1,43 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+// Ensure that we can restore a stack of a finished thread.
+
+int g_data;
+
+void __attribute__((noinline)) foobar(int *p) {
+ *p = 42;
+}
+
+void *Thread1(void *x) {
+ foobar(&g_data);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ sleep(1);
+ g_data = 43;
+ return NULL;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Write of size 4 at {{.*}} by thread T2:
+// CHECK: Previous write of size 4 at {{.*}} by thread T1:
+// CHECK: #0 foobar
+// CHECK: #1 Thread1
+// CHECK: Thread T1 (tid={{.*}}, finished) created by main thread at:
+// CHECK: #0 pthread_create
+// CHECK: #1 main
diff --git a/test/tsan/signal_errno.cc b/test/tsan/signal_errno.cc
new file mode 100644
index 000000000000..1fa20f36810b
--- /dev/null
+++ b/test/tsan/signal_errno.cc
@@ -0,0 +1,49 @@
+// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+
+pthread_t mainth;
+volatile int done;
+
+static void MyHandler(int, siginfo_t *s, void *c) {
+ errno = 1;
+ done = 1;
+}
+
+static void* sendsignal(void *p) {
+ sleep(1);
+ pthread_kill(mainth, SIGPROF);
+ return 0;
+}
+
+static __attribute__((noinline)) void loop() {
+ while (done == 0) {
+ volatile char *p = (char*)malloc(1);
+ p[0] = 0;
+ free((void*)p);
+ pthread_yield();
+ }
+}
+
+int main() {
+ mainth = pthread_self();
+ struct sigaction act = {};
+ act.sa_sigaction = &MyHandler;
+ sigaction(SIGPROF, &act, 0);
+ pthread_t th;
+ pthread_create(&th, 0, sendsignal, 0);
+ loop();
+ pthread_join(th, 0);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: signal handler spoils errno
+// CHECK: #0 MyHandler(int, {{(__)?}}siginfo{{(_t)?}}*, void*) {{.*}}signal_errno.cc
+// CHECK: main
+// CHECK: SUMMARY: ThreadSanitizer: signal handler spoils errno{{.*}}MyHandler
+
diff --git a/test/tsan/signal_longjmp.cc b/test/tsan/signal_longjmp.cc
new file mode 100644
index 000000000000..84b0682dcbaf
--- /dev/null
+++ b/test/tsan/signal_longjmp.cc
@@ -0,0 +1,69 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+// Test case for longjumping out of signal handler:
+// https://code.google.com/p/thread-sanitizer/issues/detail?id=75
+
+#include <setjmp.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/mman.h>
+
+sigjmp_buf fault_jmp;
+volatile int fault_expected;
+
+void sigfault_handler(int sig) {
+ if (!fault_expected)
+ abort();
+
+ /* just return from sighandler to proper place */
+ fault_expected = 0;
+ siglongjmp(fault_jmp, 1);
+}
+
+#define MUST_FAULT(code) do { \
+ fault_expected = 1; \
+ if (!sigsetjmp(fault_jmp, 1)) { \
+ code; /* should pagefault -> sihandler does longjmp */ \
+ fprintf(stderr, "%s not faulted\n", #code); \
+ abort(); \
+ } else { \
+ fprintf(stderr, "%s faulted ok\n", #code); \
+ } \
+} while (0)
+
+int main() {
+ struct sigaction act;
+ act.sa_handler = sigfault_handler;
+ act.sa_flags = 0;
+ if (sigemptyset(&act.sa_mask)) {
+ perror("sigemptyset");
+ exit(1);
+ }
+
+ if (sigaction(SIGSEGV, &act, NULL)) {
+ perror("sigaction");
+ exit(1);
+ }
+
+ void *mem = mmap(0, 4096, PROT_NONE, MAP_PRIVATE | MAP_ANON,
+ -1, 0);
+
+ MUST_FAULT(((volatile int *volatile)mem)[0] = 0);
+ MUST_FAULT(((volatile int *volatile)mem)[1] = 1);
+ MUST_FAULT(((volatile int *volatile)mem)[3] = 1);
+
+ // Ensure that tsan does not think that we are
+ // in a signal handler.
+ void *volatile p = malloc(10);
+ ((volatile int*)p)[1] = 1;
+ free((void*)p);
+
+ munmap(p, 4096);
+
+ fprintf(stderr, "DONE\n");
+ return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: DONE
diff --git a/test/tsan/signal_malloc.cc b/test/tsan/signal_malloc.cc
new file mode 100644
index 000000000000..06932fba42db
--- /dev/null
+++ b/test/tsan/signal_malloc.cc
@@ -0,0 +1,26 @@
+// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static void handler(int, siginfo_t*, void*) {
+ // CHECK: WARNING: ThreadSanitizer: signal-unsafe call inside of a signal
+ // CHECK: #0 malloc
+ // CHECK: #{{(1|2)}} handler(int, {{(__)?}}siginfo{{(_t)?}}*, void*) {{.*}}signal_malloc.cc:[[@LINE+2]]
+ // CHECK: SUMMARY: ThreadSanitizer: signal-unsafe call inside of a signal{{.*}}handler
+ volatile char *p = (char*)malloc(1);
+ p[0] = 0;
+ free((void*)p);
+}
+
+int main() {
+ struct sigaction act = {};
+ act.sa_sigaction = &handler;
+ sigaction(SIGPROF, &act, 0);
+ kill(getpid(), SIGPROF);
+ sleep(1);
+ return 0;
+}
+
diff --git a/test/tsan/signal_recursive.cc b/test/tsan/signal_recursive.cc
new file mode 100644
index 000000000000..bbb6807586a5
--- /dev/null
+++ b/test/tsan/signal_recursive.cc
@@ -0,0 +1,132 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+// Test case for recursive signal handlers, adopted from:
+// https://code.google.com/p/thread-sanitizer/issues/detail?id=71
+
+#include <pthread.h>
+#include <semaphore.h>
+#include <signal.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "process_sleep.h"
+
+static const int kSigSuspend = SIGUSR1;
+static const int kSigRestart = SIGUSR2;
+static sigset_t g_suspend_handler_mask;
+
+static sem_t g_thread_suspend_ack_sem;
+
+static bool g_busy_thread_received_restart;
+
+static volatile bool g_busy_thread_garbage_collected;
+
+static void SaveRegistersInStack() {
+ // Mono walks thread stacks to detect unreferenced objects.
+ // If last object reference is kept in register the object will be collected
+ // This is why threads can't be suspended with something like pthread_suspend
+};
+
+static void fail(const char *what) {
+ fprintf(stderr, "FAILED: %s (errno=%d)\n", what, errno);
+ exit(1);
+}
+
+static void SuspendHandler(int sig) {
+ int old_errno = errno;
+ SaveRegistersInStack();
+ // Acknowledge that thread is saved and suspended
+ if (sem_post(&g_thread_suspend_ack_sem) != 0)
+ fail("sem_post failed");
+
+ do {
+ g_busy_thread_received_restart = false;
+ if (sigsuspend(&g_suspend_handler_mask) != -1 || errno != EINTR)
+ fail("sigsuspend failed");
+ } while (!g_busy_thread_received_restart);
+
+ // Acknowledge that thread restarted
+ if (sem_post(&g_thread_suspend_ack_sem) != 0)
+ fail("sem_post failed");
+
+ g_busy_thread_garbage_collected = true;
+
+ errno = old_errno;
+}
+
+static void RestartHandler(int sig) {
+ g_busy_thread_received_restart = true;
+}
+
+static void StopWorld(pthread_t thread) {
+ if (pthread_kill(thread, kSigSuspend) != 0)
+ fail("pthread_kill failed");
+
+ while (sem_wait(&g_thread_suspend_ack_sem) != 0) {
+ if (errno != EINTR)
+ fail("sem_wait failed");
+ }
+}
+
+static void StartWorld(pthread_t thread) {
+ if (pthread_kill(thread, kSigRestart) != 0)
+ fail("pthread_kill failed");
+
+ while (sem_wait(&g_thread_suspend_ack_sem) != 0) {
+ if (errno != EINTR)
+ fail("sem_wait failed");
+ }
+}
+
+static void CollectGarbage(pthread_t thread) {
+ StopWorld(thread);
+ // Walk stacks
+ process_sleep(1);
+ StartWorld(thread);
+}
+
+static void Init() {
+ if (sigfillset(&g_suspend_handler_mask) != 0)
+ fail("sigfillset failed");
+ if (sigdelset(&g_suspend_handler_mask, kSigRestart) != 0)
+ fail("sigdelset failed");
+ if (sem_init(&g_thread_suspend_ack_sem, 0, 0) != 0)
+ fail("sem_init failed");
+
+ struct sigaction act = {};
+ act.sa_flags = SA_RESTART;
+ sigfillset(&act.sa_mask);
+ act.sa_handler = &SuspendHandler;
+ if (sigaction(kSigSuspend, &act, NULL) != 0)
+ fail("sigaction failed");
+ act.sa_handler = &RestartHandler;
+ if (sigaction(kSigRestart, &act, NULL) != 0)
+ fail("sigaction failed");
+}
+
+void* BusyThread(void *arg) {
+ (void)arg;
+ while (!g_busy_thread_garbage_collected) {
+ usleep(100); // Tsan deadlocks without these sleeps
+ }
+ return NULL;
+}
+
+int main(int argc, const char *argv[]) {
+ Init();
+ pthread_t busy_thread;
+ if (pthread_create(&busy_thread, NULL, &BusyThread, NULL) != 0)
+ fail("pthread_create failed");
+ CollectGarbage(busy_thread);
+ if (pthread_join(busy_thread, 0) != 0)
+ fail("pthread_join failed");
+ fprintf(stderr, "DONE\n");
+ return 0;
+}
+
+// CHECK-NOT: FAILED
+// CHECK-NOT: ThreadSanitizer CHECK failed
+// CHECK-NOT: WARNING: ThreadSanitizer:
+// CHECK: DONE
diff --git a/test/tsan/signal_sync.cc b/test/tsan/signal_sync.cc
new file mode 100644
index 000000000000..15387b754dfb
--- /dev/null
+++ b/test/tsan/signal_sync.cc
@@ -0,0 +1,58 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <errno.h>
+
+volatile int X;
+
+static void handler(int sig) {
+ (void)sig;
+ if (X != 42)
+ printf("bad");
+}
+
+static void* thr(void *p) {
+ for (int i = 0; i != 1000; i++)
+ usleep(1000);
+ return 0;
+}
+
+int main() {
+ const int kThreads = 10;
+ pthread_t th[kThreads];
+ for (int i = 0; i < kThreads; i++)
+ pthread_create(&th[i], 0, thr, 0);
+
+ X = 42;
+
+ struct sigaction act = {};
+ act.sa_handler = &handler;
+ if (sigaction(SIGPROF, &act, 0)) {
+ perror("sigaction");
+ exit(1);
+ }
+
+ itimerval t;
+ t.it_value.tv_sec = 0;
+ t.it_value.tv_usec = 10;
+ t.it_interval = t.it_value;
+ if (setitimer(ITIMER_PROF, &t, 0)) {
+ perror("setitimer");
+ exit(1);
+ }
+
+ for (int i = 0; i < kThreads; i++)
+ pthread_join(th[i], 0);
+
+ fprintf(stderr, "DONE\n");
+ return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer:
+// CHECK: DONE
+// CHECK-NOT: WARNING: ThreadSanitizer:
diff --git a/test/tsan/signal_write.cc b/test/tsan/signal_write.cc
new file mode 100644
index 000000000000..626d87a7acc7
--- /dev/null
+++ b/test/tsan/signal_write.cc
@@ -0,0 +1,27 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static void handler(int, siginfo_t*, void*) {
+ const char *str = "HELLO FROM SIGNAL\n";
+ write(2, str, strlen(str));
+}
+
+int main() {
+ struct sigaction act = {};
+ act.sa_sigaction = &handler;
+ sigaction(SIGPROF, &act, 0);
+ kill(getpid(), SIGPROF);
+ sleep(1);
+ fprintf(stderr, "DONE\n");
+ return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: HELLO FROM SIGNAL
+// CHECK: DONE
+
diff --git a/test/tsan/sigsuspend.cc b/test/tsan/sigsuspend.cc
new file mode 100644
index 000000000000..a5930d4e87aa
--- /dev/null
+++ b/test/tsan/sigsuspend.cc
@@ -0,0 +1,44 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+// Always enable asserts.
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <stdio.h>
+
+static bool signal_handler_ran = false;
+
+void do_nothing_signal_handler(int signum) {
+ write(1, "HANDLER\n", 8);
+ signal_handler_ran = true;
+}
+
+int main() {
+ const int kSignalToTest = SIGSYS;
+ assert(SIG_ERR != signal(kSignalToTest, do_nothing_signal_handler));
+ sigset_t empty_set;
+ assert(0 == sigemptyset(&empty_set));
+ sigset_t one_signal = empty_set;
+ assert(0 == sigaddset(&one_signal, kSignalToTest));
+ sigset_t old_set;
+ assert(0 == sigprocmask(SIG_BLOCK, &one_signal, &old_set));
+ raise(kSignalToTest);
+ assert(!signal_handler_ran);
+ sigset_t all_but_one;
+ assert(0 == sigfillset(&all_but_one));
+ assert(0 == sigdelset(&all_but_one, kSignalToTest));
+ sigsuspend(&all_but_one);
+ assert(signal_handler_ran);
+
+ // Restore the original set.
+ assert(0 == sigprocmask(SIG_SETMASK, &old_set, NULL));
+ printf("DONE\n");
+}
+
+// CHECK: HANDLER
+// CHECK: DONE
diff --git a/test/tsan/simple_race.c b/test/tsan/simple_race.c
new file mode 100644
index 000000000000..7b60c5ec249e
--- /dev/null
+++ b/test/tsan/simple_race.c
@@ -0,0 +1,29 @@
+// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+
+void *Thread1(void *x) {
+ sleep(1);
+ Global = 42;
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ Global = 43;
+ return NULL;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+
diff --git a/test/tsan/simple_race.cc b/test/tsan/simple_race.cc
new file mode 100644
index 000000000000..f711bb5d114d
--- /dev/null
+++ b/test/tsan/simple_race.cc
@@ -0,0 +1,29 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+
+void *Thread1(void *x) {
+ sleep(1);
+ Global++;
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ Global--;
+ return NULL;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: SUMMARY: ThreadSanitizer: data race{{.*}}Thread
diff --git a/test/tsan/simple_stack.c b/test/tsan/simple_stack.c
new file mode 100644
index 000000000000..87367033b4c9
--- /dev/null
+++ b/test/tsan/simple_stack.c
@@ -0,0 +1,66 @@
+// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+
+void __attribute__((noinline)) foo1() {
+ Global = 42;
+}
+
+void __attribute__((noinline)) bar1() {
+ volatile int tmp = 42; (void)tmp;
+ foo1();
+}
+
+void __attribute__((noinline)) foo2() {
+ volatile int v = Global; (void)v;
+}
+
+void __attribute__((noinline)) bar2() {
+ volatile int tmp = 42; (void)tmp;
+ foo2();
+}
+
+void *Thread1(void *x) {
+ sleep(1);
+ bar1();
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ bar2();
+ return NULL;
+}
+
+void StartThread(pthread_t *t, void *(*f)(void*)) {
+ pthread_create(t, NULL, f, NULL);
+}
+
+int main() {
+ pthread_t t[2];
+ StartThread(&t[0], Thread1);
+ StartThread(&t[1], Thread2);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK-NEXT: Write of size 4 at {{.*}} by thread T1:
+// CHECK-NEXT: #0 foo1{{.*}} {{.*}}simple_stack.c:9{{(:3)?}} ({{.*}})
+// CHECK-NEXT: #1 bar1{{.*}} {{.*}}simple_stack.c:14{{(:3)?}} ({{.*}})
+// CHECK-NEXT: #2 Thread1{{.*}} {{.*}}simple_stack.c:28{{(:3)?}} ({{.*}})
+// CHECK: Previous read of size 4 at {{.*}} by thread T2:
+// CHECK-NEXT: #0 foo2{{.*}} {{.*}}simple_stack.c:18{{(:3)?}} ({{.*}})
+// CHECK-NEXT: #1 bar2{{.*}} {{.*}}simple_stack.c:23{{(:3)?}} ({{.*}})
+// CHECK-NEXT: #2 Thread2{{.*}} {{.*}}simple_stack.c:33{{(:3)?}} ({{.*}})
+// CHECK: Thread T1 (tid={{.*}}, running) created by main thread at:
+// CHECK-NEXT: #0 pthread_create {{.*}} ({{.*}})
+// CHECK-NEXT: #1 StartThread{{.*}} {{.*}}simple_stack.c:38{{(:3)?}} ({{.*}})
+// CHECK-NEXT: #2 main{{.*}} {{.*}}simple_stack.c:43{{(:3)?}} ({{.*}})
+// CHECK: Thread T2 ({{.*}}) created by main thread at:
+// CHECK-NEXT: #0 pthread_create {{.*}} ({{.*}})
+// CHECK-NEXT: #1 StartThread{{.*}} {{.*}}simple_stack.c:38{{(:3)?}} ({{.*}})
+// CHECK-NEXT: #2 main{{.*}} {{.*}}simple_stack.c:44{{(:3)?}} ({{.*}})
diff --git a/test/tsan/simple_stack2.cc b/test/tsan/simple_stack2.cc
new file mode 100644
index 000000000000..b07d863e4008
--- /dev/null
+++ b/test/tsan/simple_stack2.cc
@@ -0,0 +1,53 @@
+// RUN: %clangxx_tsan -O1 %s -o %T/simple_stack2.cc.exe && %deflake %run %T/simple_stack2.cc.exe | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+
+void __attribute__((noinline)) foo1() {
+ Global = 42;
+}
+
+void __attribute__((noinline)) bar1() {
+ volatile int tmp = 42;
+ int tmp2 = tmp;
+ (void)tmp2;
+ foo1();
+}
+
+void __attribute__((noinline)) foo2() {
+ volatile int tmp = Global;
+ int tmp2 = tmp;
+ (void)tmp2;
+}
+
+void __attribute__((noinline)) bar2() {
+ volatile int tmp = 42;
+ int tmp2 = tmp;
+ (void)tmp2;
+ foo2();
+}
+
+void *Thread1(void *x) {
+ sleep(1);
+ bar1();
+ return NULL;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, NULL, Thread1, NULL);
+ bar2();
+ pthread_join(t, NULL);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK-NEXT: Write of size 4 at {{.*}} by thread T1:
+// CHECK-NEXT: #0 foo1{{.*}} {{.*}}simple_stack2.cc:9{{(:3)?}} (simple_stack2.cc.exe+{{.*}})
+// CHECK-NEXT: #1 bar1{{.*}} {{.*}}simple_stack2.cc:16{{(:3)?}} (simple_stack2.cc.exe+{{.*}})
+// CHECK-NEXT: #2 Thread1{{.*}} {{.*}}simple_stack2.cc:34{{(:3)?}} (simple_stack2.cc.exe+{{.*}})
+// CHECK: Previous read of size 4 at {{.*}} by main thread:
+// CHECK-NEXT: #0 foo2{{.*}} {{.*}}simple_stack2.cc:20{{(:3)?}} (simple_stack2.cc.exe+{{.*}})
+// CHECK-NEXT: #1 bar2{{.*}} {{.*}}simple_stack2.cc:29{{(:3)?}} (simple_stack2.cc.exe+{{.*}})
+// CHECK-NEXT: #2 main{{.*}} {{.*}}simple_stack2.cc:41{{(:3)?}} (simple_stack2.cc.exe+{{.*}})
diff --git a/test/tsan/sleep_sync.cc b/test/tsan/sleep_sync.cc
new file mode 100644
index 000000000000..c7614e16bf3e
--- /dev/null
+++ b/test/tsan/sleep_sync.cc
@@ -0,0 +1,30 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <unistd.h>
+
+int X = 0;
+
+void MySleep() {
+ sleep(1);
+}
+
+void *Thread(void *p) {
+ MySleep(); // Assume the main thread has done the write.
+ X = 42;
+ return 0;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ X = 43;
+ pthread_join(t, 0);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// ...
+// CHECK: As if synchronized via sleep:
+// CHECK-NEXT: #0 sleep
+// CHECK-NEXT: #1 MySleep
+// CHECK-NEXT: #2 Thread
diff --git a/test/tsan/sleep_sync2.cc b/test/tsan/sleep_sync2.cc
new file mode 100644
index 000000000000..4e616992ecc9
--- /dev/null
+++ b/test/tsan/sleep_sync2.cc
@@ -0,0 +1,22 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <unistd.h>
+
+int X = 0;
+
+void *Thread(void *p) {
+ X = 42;
+ return 0;
+}
+
+int main() {
+ pthread_t t;
+ sleep(1);
+ pthread_create(&t, 0, Thread, 0);
+ X = 43;
+ pthread_join(t, 0);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK-NOT: As if synchronized via sleep
diff --git a/test/tsan/stack_race.cc b/test/tsan/stack_race.cc
new file mode 100644
index 000000000000..2e02f46a281f
--- /dev/null
+++ b/test/tsan/stack_race.cc
@@ -0,0 +1,22 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stddef.h>
+#include <unistd.h>
+
+void *Thread(void *a) {
+ sleep(1);
+ *(int*)a = 43;
+ return 0;
+}
+
+int main() {
+ int Var = 42;
+ pthread_t t;
+ pthread_create(&t, 0, Thread, &Var);
+ Var = 43;
+ pthread_join(t, 0);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Location is stack of main thread.
+
diff --git a/test/tsan/stack_race2.cc b/test/tsan/stack_race2.cc
new file mode 100644
index 000000000000..818db367bab6
--- /dev/null
+++ b/test/tsan/stack_race2.cc
@@ -0,0 +1,29 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stddef.h>
+#include <unistd.h>
+
+void *Thread2(void *a) {
+ sleep(1);
+ *(int*)a = 43;
+ return 0;
+}
+
+void *Thread(void *a) {
+ int Var = 42;
+ pthread_t t;
+ pthread_create(&t, 0, Thread2, &Var);
+ Var = 42;
+ pthread_join(t, 0);
+ return 0;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ pthread_join(t, 0);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Location is stack of thread T1.
+
diff --git a/test/tsan/static_init1.cc b/test/tsan/static_init1.cc
new file mode 100644
index 000000000000..3e5fb14ba44b
--- /dev/null
+++ b/test/tsan/static_init1.cc
@@ -0,0 +1,27 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+struct P {
+ int x;
+ int y;
+};
+
+void *Thread(void *x) {
+ static P p = {rand(), rand()};
+ if (p.x > RAND_MAX || p.y > RAND_MAX)
+ exit(1);
+ return 0;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], 0, Thread, 0);
+ pthread_create(&t[1], 0, Thread, 0);
+ pthread_join(t[0], 0);
+ pthread_join(t[1], 0);
+ printf("PASS\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/static_init2.cc b/test/tsan/static_init2.cc
new file mode 100644
index 000000000000..667aed1343dc
--- /dev/null
+++ b/test/tsan/static_init2.cc
@@ -0,0 +1,33 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+struct Cache {
+ int x;
+ explicit Cache(int x)
+ : x(x) {
+ }
+};
+
+void foo(Cache *my) {
+ static Cache *c = my ? my : new Cache(rand());
+ if (c->x >= RAND_MAX)
+ exit(1);
+}
+
+void *Thread(void *x) {
+ foo(new Cache(rand()));
+ return 0;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], 0, Thread, 0);
+ pthread_create(&t[1], 0, Thread, 0);
+ pthread_join(t[0], 0);
+ pthread_join(t[1], 0);
+ printf("PASS\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/static_init3.cc b/test/tsan/static_init3.cc
new file mode 100644
index 000000000000..3b9fe62ae2bc
--- /dev/null
+++ b/test/tsan/static_init3.cc
@@ -0,0 +1,47 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sched.h>
+
+struct Cache {
+ int x;
+};
+
+Cache g_cache;
+
+Cache *CreateCache() {
+ g_cache.x = rand();
+ return &g_cache;
+}
+
+_Atomic(Cache*) queue;
+
+void *Thread1(void *x) {
+ static Cache *c = CreateCache();
+ __c11_atomic_store(&queue, c, 0);
+ return 0;
+}
+
+void *Thread2(void *x) {
+ Cache *c = 0;
+ for (;;) {
+ c = __c11_atomic_load(&queue, 0);
+ if (c)
+ break;
+ sched_yield();
+ }
+ if (c->x >= RAND_MAX)
+ exit(1);
+ return 0;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], 0, Thread1, 0);
+ pthread_create(&t[1], 0, Thread2, 0);
+ pthread_join(t[0], 0);
+ pthread_join(t[1], 0);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/static_init4.cc b/test/tsan/static_init4.cc
new file mode 100644
index 000000000000..85835a2520f7
--- /dev/null
+++ b/test/tsan/static_init4.cc
@@ -0,0 +1,37 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sched.h>
+
+struct Cache {
+ int x;
+ explicit Cache(int x)
+ : x(x) {
+ }
+};
+
+int g_other;
+
+Cache *CreateCache() {
+ g_other = rand();
+ return new Cache(rand());
+}
+
+void *Thread1(void *x) {
+ static Cache *c = CreateCache();
+ if (c->x == g_other)
+ exit(1);
+ return 0;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], 0, Thread1, 0);
+ pthread_create(&t[1], 0, Thread1, 0);
+ pthread_join(t[0], 0);
+ pthread_join(t[1], 0);
+ printf("PASS\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/static_init5.cc b/test/tsan/static_init5.cc
new file mode 100644
index 000000000000..961e3a3b6329
--- /dev/null
+++ b/test/tsan/static_init5.cc
@@ -0,0 +1,42 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sched.h>
+
+struct Cache {
+ int x;
+ explicit Cache(int x)
+ : x(x) {
+ }
+};
+
+void *AsyncInit(void *p) {
+ return new Cache((int)(long)p);
+}
+
+Cache *CreateCache() {
+ pthread_t t;
+ pthread_create(&t, 0, AsyncInit, (void*)(long)rand());
+ void *res;
+ pthread_join(t, &res);
+ return (Cache*)res;
+}
+
+void *Thread1(void *x) {
+ static Cache *c = CreateCache();
+ if (c->x >= RAND_MAX)
+ exit(1);
+ return 0;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], 0, Thread1, 0);
+ pthread_create(&t[1], 0, Thread1, 0);
+ pthread_join(t[0], 0);
+ pthread_join(t[1], 0);
+ printf("PASS\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/static_init6.cc b/test/tsan/static_init6.cc
new file mode 100644
index 000000000000..77253eac173f
--- /dev/null
+++ b/test/tsan/static_init6.cc
@@ -0,0 +1,42 @@
+// RUN: %clangxx_tsan -static-libstdc++ -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sched.h>
+
+struct Cache {
+ int x;
+ explicit Cache(int x)
+ : x(x) {
+ }
+};
+
+void *AsyncInit(void *p) {
+ return new Cache((int)(long)p);
+}
+
+Cache *CreateCache() {
+ pthread_t t;
+ pthread_create(&t, 0, AsyncInit, (void*)(long)rand());
+ void *res;
+ pthread_join(t, &res);
+ return (Cache*)res;
+}
+
+void *Thread1(void *x) {
+ static Cache *c = CreateCache();
+ if (c->x >= RAND_MAX)
+ exit(1);
+ return 0;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], 0, Thread1, 0);
+ pthread_create(&t[1], 0, Thread1, 0);
+ pthread_join(t[0], 0);
+ pthread_join(t[1], 0);
+ printf("PASS\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/sunrpc.cc b/test/tsan/sunrpc.cc
new file mode 100644
index 000000000000..579816d64098
--- /dev/null
+++ b/test/tsan/sunrpc.cc
@@ -0,0 +1,25 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <pthread.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <stdio.h>
+
+void *thr(void *p) {
+ XDR xdrs;
+ char buf[100];
+ xdrmem_create(&xdrs, buf, sizeof(buf), XDR_ENCODE);
+ xdr_destroy(&xdrs);
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+ 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);
+ printf("DONE\n");
+ // CHECK: DONE
+ return 0;
+}
diff --git a/test/tsan/suppress_same_address.cc b/test/tsan/suppress_same_address.cc
new file mode 100644
index 000000000000..df19da1cc7ae
--- /dev/null
+++ b/test/tsan/suppress_same_address.cc
@@ -0,0 +1,29 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <unistd.h>
+
+volatile int X;
+
+void *Thread1(void *x) {
+ sleep(1);
+ X = 42;
+ X = 66;
+ X = 78;
+ return 0;
+}
+
+void *Thread2(void *x) {
+ X = 11;
+ X = 99;
+ X = 73;
+ return 0;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread1, 0);
+ Thread2(0);
+ pthread_join(t, 0);
+}
+
+// CHECK: ThreadSanitizer: reported 1 warnings
diff --git a/test/tsan/suppress_same_stacks.cc b/test/tsan/suppress_same_stacks.cc
new file mode 100644
index 000000000000..9305650eaa17
--- /dev/null
+++ b/test/tsan/suppress_same_stacks.cc
@@ -0,0 +1,27 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+
+volatile int N; // Prevent loop unrolling.
+int **data;
+
+void *Thread1(void *x) {
+ for (int i = 0; i < N; i++)
+ data[i][0] = 42;
+ return 0;
+}
+
+int main() {
+ N = 4;
+ data = new int*[N];
+ for (int i = 0; i < N; i++)
+ data[i] = new int;
+ pthread_t t;
+ pthread_create(&t, 0, Thread1, 0);
+ Thread1(0);
+ pthread_join(t, 0);
+ for (int i = 0; i < N; i++)
+ delete data[i];
+ delete[] data;
+}
+
+// CHECK: ThreadSanitizer: reported 1 warnings
diff --git a/test/tsan/suppressions_global.cc b/test/tsan/suppressions_global.cc
new file mode 100644
index 000000000000..c808a63d9e84
--- /dev/null
+++ b/test/tsan/suppressions_global.cc
@@ -0,0 +1,29 @@
+// RUN: %clang_tsan -O1 %s -o %t && TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+
+int RacyGlobal;
+
+void *Thread1(void *x) {
+ RacyGlobal = 42;
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ RacyGlobal = 43;
+ return NULL;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ printf("OK\n");
+ return 0;
+}
+
+// CHECK-NOT: failed to open suppressions file
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+
diff --git a/test/tsan/suppressions_global.cc.supp b/test/tsan/suppressions_global.cc.supp
new file mode 100644
index 000000000000..5fa8a2e43a93
--- /dev/null
+++ b/test/tsan/suppressions_global.cc.supp
@@ -0,0 +1,2 @@
+race:RacyGlobal
+
diff --git a/test/tsan/suppressions_race.cc b/test/tsan/suppressions_race.cc
new file mode 100644
index 000000000000..1d72874d9586
--- /dev/null
+++ b/test/tsan/suppressions_race.cc
@@ -0,0 +1,31 @@
+// RUN: %clang_tsan -O1 %s -o %t && TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+
+void *Thread1(void *x) {
+ sleep(1);
+ Global = 42;
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ Global = 43;
+ return NULL;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ printf("OK\n");
+ return 0;
+}
+
+// CHECK-NOT: failed to open suppressions file
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+
diff --git a/test/tsan/suppressions_race.cc.supp b/test/tsan/suppressions_race.cc.supp
new file mode 100644
index 000000000000..cbdba76ea93a
--- /dev/null
+++ b/test/tsan/suppressions_race.cc.supp
@@ -0,0 +1,2 @@
+race:Thread1
+
diff --git a/test/tsan/suppressions_race2.cc b/test/tsan/suppressions_race2.cc
new file mode 100644
index 000000000000..4ababddf6311
--- /dev/null
+++ b/test/tsan/suppressions_race2.cc
@@ -0,0 +1,31 @@
+// RUN: %clang_tsan -O1 %s -o %t && TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+
+void *Thread1(void *x) {
+ Global = 42;
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ sleep(1);
+ Global = 43;
+ return NULL;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ printf("OK\n");
+ return 0;
+}
+
+// CHECK-NOT: failed to open suppressions file
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+
diff --git a/test/tsan/suppressions_race2.cc.supp b/test/tsan/suppressions_race2.cc.supp
new file mode 100644
index 000000000000..b3c4dbc59363
--- /dev/null
+++ b/test/tsan/suppressions_race2.cc.supp
@@ -0,0 +1,2 @@
+race:Thread2
+
diff --git a/test/tsan/test_output.sh b/test/tsan/test_output.sh
new file mode 100755
index 000000000000..bce0fe8b5511
--- /dev/null
+++ b/test/tsan/test_output.sh
@@ -0,0 +1,66 @@
+#!/bin/bash
+
+ulimit -s 8192
+set -e # fail on any error
+
+HERE=$(dirname $0)
+TSAN_DIR=$(dirname $0)/../../lib/tsan
+
+# Assume clang and clang++ are in path.
+: ${CC:=clang}
+: ${CXX:=clang++}
+: ${FILECHECK:=FileCheck}
+
+# TODO: add testing for all of -O0...-O3
+CFLAGS="-fsanitize=thread -O2 -g -Wall"
+LDFLAGS="-pthread -ldl -lrt -lm -Wl,--whole-archive $TSAN_DIR/rtl/libtsan.a -Wl,--no-whole-archive"
+
+test_file() {
+ SRC=$1
+ COMPILER=$2
+ echo ----- TESTING $(basename $1)
+ OBJ=$SRC.o
+ EXE=$SRC.exe
+ $COMPILER $SRC $CFLAGS -c -o $OBJ
+ $COMPILER $OBJ $LDFLAGS -o $EXE
+ RES=$($EXE 2>&1 || true)
+ printf "%s\n" "$RES" | $FILECHECK $SRC
+ if [ "$3" == "" ]; then
+ rm -f $EXE $OBJ
+ fi
+}
+
+if [ "$1" == "" ]; then
+ for c in $HERE/*.{c,cc}; do
+ if [[ $c == */failing_* ]]; then
+ echo SKIPPING FAILING TEST $c
+ continue
+ fi
+ if [[ $c == */load_shared_lib.cc ]]; then
+ echo TEST $c is not supported
+ continue
+ fi
+ if [[ $c == */*blacklist*.cc ]]; then
+ echo TEST $c is not supported
+ continue
+ fi
+ if [ "`grep "TSAN_OPTIONS" $c`" ]; then
+ echo SKIPPING $c -- requires TSAN_OPTIONS
+ continue
+ fi
+ if [ "`grep "XFAIL" $c`" ]; then
+ echo SKIPPING $c -- has XFAIL
+ continue
+ fi
+ COMPILER=$CXX
+ case $c in
+ *.c) COMPILER=$CC
+ esac
+ test_file $c $COMPILER &
+ done
+ for job in `jobs -p`; do
+ wait $job || exit 1
+ done
+else
+ test_file $HERE/$1 $CXX "DUMP"
+fi
diff --git a/test/tsan/thread_detach.c b/test/tsan/thread_detach.c
new file mode 100644
index 000000000000..32cf641b141a
--- /dev/null
+++ b/test/tsan/thread_detach.c
@@ -0,0 +1,20 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+void *Thread(void *x) {
+ return 0;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ sleep(1);
+ pthread_detach(t);
+ printf("PASS\n");
+ return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: thread leak
+// CHECK: PASS
diff --git a/test/tsan/thread_end_with_ignore.cc b/test/tsan/thread_end_with_ignore.cc
new file mode 100644
index 000000000000..79bb08d64bcb
--- /dev/null
+++ b/test/tsan/thread_end_with_ignore.cc
@@ -0,0 +1,24 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+
+extern "C" void AnnotateIgnoreReadsBegin(const char *f, int l);
+
+void *Thread(void *x) {
+ AnnotateIgnoreReadsBegin("", 0);
+ return 0;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ pthread_join(t, 0);
+}
+
+// CHECK: ThreadSanitizer: thread T1 finished with ignores enabled, created at:
+// CHECK: #0 pthread_create
+// CHECK: #1 main
+// CHECK: Ignore was enabled at:
+// CHECK: #0 AnnotateIgnoreReadsBegin
+// CHECK: #1 Thread
+
diff --git a/test/tsan/thread_end_with_ignore2.cc b/test/tsan/thread_end_with_ignore2.cc
new file mode 100644
index 000000000000..9387ea488d5a
--- /dev/null
+++ b/test/tsan/thread_end_with_ignore2.cc
@@ -0,0 +1,12 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+extern "C" void AnnotateIgnoreWritesBegin(const char *f, int l);
+
+int main() {
+ AnnotateIgnoreWritesBegin("", 0);
+}
+
+// CHECK: ThreadSanitizer: main thread finished with ignores enabled
+// CHECK: Ignore was enabled at:
+// CHECK: #0 AnnotateIgnoreWritesBegin
+// CHECK: #1 main
+
diff --git a/test/tsan/thread_end_with_ignore3.cc b/test/tsan/thread_end_with_ignore3.cc
new file mode 100644
index 000000000000..55688b2a543f
--- /dev/null
+++ b/test/tsan/thread_end_with_ignore3.cc
@@ -0,0 +1,22 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+extern "C" void AnnotateIgnoreReadsBegin(const char *f, int l);
+extern "C" void AnnotateIgnoreReadsEnd(const char *f, int l);
+
+int main() {
+ AnnotateIgnoreReadsBegin("", 0);
+ AnnotateIgnoreReadsBegin("", 0);
+ AnnotateIgnoreReadsEnd("", 0);
+ AnnotateIgnoreReadsEnd("", 0);
+ AnnotateIgnoreReadsBegin("", 0);
+ AnnotateIgnoreReadsBegin("", 0);
+ AnnotateIgnoreReadsEnd("", 0);
+}
+
+// CHECK: ThreadSanitizer: main thread finished with ignores enabled
+// CHECK: Ignore was enabled at:
+// CHECK: #0 AnnotateIgnoreReadsBegin
+// CHECK: #1 main {{.*}}thread_end_with_ignore3.cc:10
+// CHECK: Ignore was enabled at:
+// CHECK: #0 AnnotateIgnoreReadsBegin
+// CHECK: #1 main {{.*}}thread_end_with_ignore3.cc:11
+
diff --git a/test/tsan/thread_leak.c b/test/tsan/thread_leak.c
new file mode 100644
index 000000000000..9b850dd4b567
--- /dev/null
+++ b/test/tsan/thread_leak.c
@@ -0,0 +1,17 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+
+void *Thread(void *x) {
+ return 0;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ pthread_join(t, 0);
+ printf("PASS\n");
+ return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: thread leak
diff --git a/test/tsan/thread_leak2.c b/test/tsan/thread_leak2.c
new file mode 100644
index 000000000000..fc2942b2a05d
--- /dev/null
+++ b/test/tsan/thread_leak2.c
@@ -0,0 +1,17 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+
+void *Thread(void *x) {
+ return 0;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ pthread_detach(t);
+ printf("PASS\n");
+ return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: thread leak
diff --git a/test/tsan/thread_leak3.c b/test/tsan/thread_leak3.c
new file mode 100644
index 000000000000..f4db484219a0
--- /dev/null
+++ b/test/tsan/thread_leak3.c
@@ -0,0 +1,17 @@
+// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <unistd.h>
+
+void *Thread(void *x) {
+ return 0;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ sleep(1);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: thread leak
+// CHECK: SUMMARY: ThreadSanitizer: thread leak{{.*}}main
diff --git a/test/tsan/thread_leak4.c b/test/tsan/thread_leak4.c
new file mode 100644
index 000000000000..0d3b8307000a
--- /dev/null
+++ b/test/tsan/thread_leak4.c
@@ -0,0 +1,18 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <unistd.h>
+#include <stdio.h>
+
+void *Thread(void *x) {
+ sleep(10);
+ return 0;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ printf("OK\n");
+ return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: thread leak
diff --git a/test/tsan/thread_leak5.c b/test/tsan/thread_leak5.c
new file mode 100644
index 000000000000..ca244a9f24e1
--- /dev/null
+++ b/test/tsan/thread_leak5.c
@@ -0,0 +1,20 @@
+// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <unistd.h>
+
+void *Thread(void *x) {
+ return 0;
+}
+
+int main() {
+ volatile int N = 5; // prevent loop unrolling
+ for (int i = 0; i < N; i++) {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ }
+ sleep(1);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: thread leak
+// CHECK: And 4 more similar thread leaks
diff --git a/test/tsan/thread_name.cc b/test/tsan/thread_name.cc
new file mode 100644
index 000000000000..a790c668c084
--- /dev/null
+++ b/test/tsan/thread_name.cc
@@ -0,0 +1,47 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#if defined(__linux__)
+#define USE_PTHREAD_SETNAME_NP __GLIBC_PREREQ(2, 12)
+#elif defined(__FreeBSD__)
+#include <pthread_np.h>
+#define USE_PTHREAD_SETNAME_NP 1
+#define pthread_setname_np pthread_set_name_np
+#else
+#define USE_PTHREAD_SETNAME_NP 0
+#endif
+
+extern "C" void AnnotateThreadName(const char *f, int l, const char *name);
+
+int Global;
+
+void *Thread1(void *x) {
+ sleep(1);
+ AnnotateThreadName(__FILE__, __LINE__, "Thread1");
+ Global++;
+ return NULL;
+}
+
+void *Thread2(void *x) {
+#if USE_PTHREAD_SETNAME_NP
+ pthread_setname_np(pthread_self(), "Thread2");
+#else
+ AnnotateThreadName(__FILE__, __LINE__, "Thread2");
+#endif
+ Global--;
+ return NULL;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Thread T1 'Thread1'
+// CHECK: Thread T2 'Thread2'
diff --git a/test/tsan/thread_name2.cc b/test/tsan/thread_name2.cc
new file mode 100644
index 000000000000..6a3dafe9c763
--- /dev/null
+++ b/test/tsan/thread_name2.cc
@@ -0,0 +1,36 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#if defined(__FreeBSD__)
+#include <pthread_np.h>
+#define pthread_setname_np pthread_set_name_np
+#endif
+
+int Global;
+
+void *Thread1(void *x) {
+ sleep(1);
+ Global++;
+ return 0;
+}
+
+void *Thread2(void *x) {
+ pthread_setname_np(pthread_self(), "foobar2");
+ Global--;
+ return 0;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], 0, Thread1, 0);
+ pthread_create(&t[1], 0, Thread2, 0);
+ pthread_setname_np(t[0], "foobar1");
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Thread T1 'foobar1'
+// CHECK: Thread T2 'foobar2'
diff --git a/test/tsan/tiny_race.c b/test/tsan/tiny_race.c
new file mode 100644
index 000000000000..c10eab15c5a9
--- /dev/null
+++ b/test/tsan/tiny_race.c
@@ -0,0 +1,21 @@
+// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <unistd.h>
+
+int Global;
+
+void *Thread1(void *x) {
+ sleep(1);
+ Global = 42;
+ return x;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread1, 0);
+ Global = 43;
+ pthread_join(t, 0);
+ return Global;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/tls_race.cc b/test/tsan/tls_race.cc
new file mode 100644
index 000000000000..18589347e806
--- /dev/null
+++ b/test/tsan/tls_race.cc
@@ -0,0 +1,21 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stddef.h>
+#include <unistd.h>
+
+void *Thread(void *a) {
+ sleep(1);
+ *(int*)a = 43;
+ return 0;
+}
+
+int main() {
+ static __thread int Var = 42;
+ pthread_t t;
+ pthread_create(&t, 0, Thread, &Var);
+ Var = 43;
+ pthread_join(t, 0);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Location is TLS of main thread.
diff --git a/test/tsan/tls_race2.cc b/test/tsan/tls_race2.cc
new file mode 100644
index 000000000000..0ca629ada5cc
--- /dev/null
+++ b/test/tsan/tls_race2.cc
@@ -0,0 +1,29 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stddef.h>
+#include <unistd.h>
+
+void *Thread2(void *a) {
+ sleep(1);
+ *(int*)a = 43;
+ return 0;
+}
+
+void *Thread(void *a) {
+ static __thread int Var = 42;
+ pthread_t t;
+ pthread_create(&t, 0, Thread2, &Var);
+ Var = 42;
+ pthread_join(t, 0);
+ return 0;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ pthread_join(t, 0);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Location is TLS of thread T1.
+
diff --git a/test/tsan/tsan-vs-gvn.cc b/test/tsan/tsan-vs-gvn.cc
new file mode 100644
index 000000000000..950f5d30d4da
--- /dev/null
+++ b/test/tsan/tsan-vs-gvn.cc
@@ -0,0 +1,38 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O2 %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O3 %s -o %t && %run %t 2>&1 | FileCheck %s
+//
+// Check that load widening is not tsan-hostile.
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+
+struct {
+ int i;
+ char c1, c2, c3, c4;
+} S;
+
+int G;
+
+void *Thread1(void *x) {
+ G = S.c1 + S.c3;
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ S.c2 = 1;
+ return NULL;
+}
+
+int main() {
+ pthread_t t[2];
+ memset(&S, 123, sizeof(S));
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ printf("PASS\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+// CHECK: PASS
diff --git a/test/tsan/unaligned_norace.cc b/test/tsan/unaligned_norace.cc
new file mode 100644
index 000000000000..20cb545f7426
--- /dev/null
+++ b/test/tsan/unaligned_norace.cc
@@ -0,0 +1,84 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+uint64_t objs[8*3*3*2][3];
+
+extern "C" {
+uint16_t __tsan_unaligned_read2(void *addr);
+uint32_t __tsan_unaligned_read4(void *addr);
+uint64_t __tsan_unaligned_read8(void *addr);
+void __tsan_unaligned_write2(void *addr, uint16_t v);
+void __tsan_unaligned_write4(void *addr, uint32_t v);
+void __tsan_unaligned_write8(void *addr, uint64_t v);
+}
+
+static void access(char *p, int sz, int rw) {
+ if (rw) {
+ switch (sz) {
+ case 0: __tsan_unaligned_write2(p, 0); break;
+ case 1: __tsan_unaligned_write4(p, 0); break;
+ case 2: __tsan_unaligned_write8(p, 0); break;
+ default: exit(1);
+ }
+ } else {
+ switch (sz) {
+ case 0: __tsan_unaligned_read2(p); break;
+ case 1: __tsan_unaligned_read4(p); break;
+ case 2: __tsan_unaligned_read8(p); break;
+ default: exit(1);
+ }
+ }
+}
+
+static int accesssize(int sz) {
+ switch (sz) {
+ case 0: return 2;
+ case 1: return 4;
+ case 2: return 8;
+ }
+ exit(1);
+}
+
+void Test(bool main) {
+ uint64_t *obj = objs[0];
+ for (int off = 0; off < 8; off++) {
+ for (int sz1 = 0; sz1 < 3; sz1++) {
+ for (int sz2 = 0; sz2 < 3; sz2++) {
+ for (int rw = 0; rw < 2; rw++) {
+ char *p = (char*)obj + off;
+ if (main) {
+ // printf("thr=%d off=%d sz1=%d sz2=%d rw=%d p=%p\n",
+ // main, off, sz1, sz2, rw, p);
+ access(p, sz1, true);
+ } else {
+ p += accesssize(sz1);
+ // printf("thr=%d off=%d sz1=%d sz2=%d rw=%d p=%p\n",
+ // main, off, sz1, sz2, rw, p);
+ access(p, sz2, rw);
+ }
+ obj += 3;
+ }
+ }
+ }
+ }
+}
+
+void *Thread(void *p) {
+ (void)p;
+ Test(false);
+ return 0;
+}
+
+int main() {
+ pthread_t th;
+ pthread_create(&th, 0, Thread, 0);
+ Test(true);
+ pthread_join(th, 0);
+ printf("OK\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer:
+// CHECK: OK
diff --git a/test/tsan/unaligned_race.cc b/test/tsan/unaligned_race.cc
new file mode 100644
index 000000000000..6e9b5a33f0da
--- /dev/null
+++ b/test/tsan/unaligned_race.cc
@@ -0,0 +1,139 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#define NOINLINE __attribute__((noinline))
+
+volatile uint64_t objs[8*2*(2 + 4 + 8)][2];
+
+extern "C" {
+uint16_t __sanitizer_unaligned_load16(volatile void *addr);
+uint32_t __sanitizer_unaligned_load32(volatile void *addr);
+uint64_t __sanitizer_unaligned_load64(volatile void *addr);
+void __sanitizer_unaligned_store16(volatile void *addr, uint16_t v);
+void __sanitizer_unaligned_store32(volatile void *addr, uint32_t v);
+void __sanitizer_unaligned_store64(volatile void *addr, uint64_t v);
+}
+
+// All this mess is to generate unique stack for each race,
+// otherwise tsan will suppress similar stacks.
+
+static NOINLINE void access(volatile char *p, int sz, int rw) {
+ if (rw) {
+ switch (sz) {
+ case 0: __sanitizer_unaligned_store16(p, 0); break;
+ case 1: __sanitizer_unaligned_store32(p, 0); break;
+ case 2: __sanitizer_unaligned_store64(p, 0); break;
+ default: exit(1);
+ }
+ } else {
+ switch (sz) {
+ case 0: __sanitizer_unaligned_load16(p); break;
+ case 1: __sanitizer_unaligned_load32(p); break;
+ case 2: __sanitizer_unaligned_load64(p); break;
+ default: exit(1);
+ }
+ }
+}
+
+static int accesssize(int sz) {
+ switch (sz) {
+ case 0: return 2;
+ case 1: return 4;
+ case 2: return 8;
+ }
+ exit(1);
+}
+
+template<int off, int off2>
+static NOINLINE void access3(bool main, int sz1, bool rw, volatile char *p) {
+ p += off;
+ if (main) {
+ access(p, sz1, true);
+ } else {
+ p += off2;
+ if (rw) {
+ *p = 42;
+ } else {
+ if (*p == 42)
+ printf("bingo!\n");
+ }
+ }
+}
+
+template<int off>
+static NOINLINE void
+access2(bool main, int sz1, int off2, bool rw, volatile char *obj) {
+ if (off2 == 0)
+ access3<off, 0>(main, sz1, rw, obj);
+ else if (off2 == 1)
+ access3<off, 1>(main, sz1, rw, obj);
+ else if (off2 == 2)
+ access3<off, 2>(main, sz1, rw, obj);
+ else if (off2 == 3)
+ access3<off, 3>(main, sz1, rw, obj);
+ else if (off2 == 4)
+ access3<off, 4>(main, sz1, rw, obj);
+ else if (off2 == 5)
+ access3<off, 5>(main, sz1, rw, obj);
+ else if (off2 == 6)
+ access3<off, 6>(main, sz1, rw, obj);
+ else if (off2 == 7)
+ access3<off, 7>(main, sz1, rw, obj);
+}
+
+static NOINLINE void
+access1(bool main, int off, int sz1, int off2, bool rw, char *obj) {
+ if (off == 0)
+ access2<0>(main, sz1, off2, rw, obj);
+ else if (off == 1)
+ access2<1>(main, sz1, off2, rw, obj);
+ else if (off == 2)
+ access2<2>(main, sz1, off2, rw, obj);
+ else if (off == 3)
+ access2<3>(main, sz1, off2, rw, obj);
+ else if (off == 4)
+ access2<4>(main, sz1, off2, rw, obj);
+ else if (off == 5)
+ access2<5>(main, sz1, off2, rw, obj);
+ else if (off == 6)
+ access2<6>(main, sz1, off2, rw, obj);
+ else if (off == 7)
+ access2<7>(main, sz1, off2, rw, obj);
+}
+
+NOINLINE void Test(bool main) {
+ volatile uint64_t *obj = objs[0];
+ for (int off = 0; off < 8; off++) {
+ for (int sz1 = 0; sz1 < 3; sz1++) {
+ for (int off2 = 0; off2 < accesssize(sz1); off2++) {
+ for (int rw = 0; rw < 2; rw++) {
+ // printf("thr=%d off=%d sz1=%d off2=%d rw=%d p=%p\n",
+ // main, off, sz1, off2, rw, obj);
+ access1(main, off, sz1, off2, rw, (char*)obj);
+ obj += 2;
+ }
+ }
+ }
+ }
+}
+
+void *Thread(void *p) {
+ (void)p;
+ sleep(1);
+ Test(false);
+ return 0;
+}
+
+int main() {
+ pthread_t th;
+ pthread_create(&th, 0, Thread, 0);
+ Test(true);
+ pthread_join(th, 0);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: ThreadSanitizer: reported 224 warnings
diff --git a/test/tsan/vfork.cc b/test/tsan/vfork.cc
new file mode 100644
index 000000000000..5ae1dd1ababd
--- /dev/null
+++ b/test/tsan/vfork.cc
@@ -0,0 +1,51 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+int fds[2];
+int X;
+
+void *Thread1(void *x) {
+ X = 42;
+ write(fds[1], "a", 1);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ char buf;
+ while (read(fds[0], &buf, 1) != 1) {
+ }
+ X = 43;
+ return NULL;
+}
+
+int main() {
+ pipe(fds);
+ int pid = vfork();
+ if (pid < 0) {
+ printf("FAIL to vfork\n");
+ exit(1);
+ }
+ if (pid == 0) { // child
+ // Closing of fds must not affect parent process.
+ // Strictly saying this is undefined behavior, because vfork child is not
+ // allowed to call any functions other than exec/exit. But this is what
+ // openjdk does.
+ close(fds[0]);
+ close(fds[1]);
+ _exit(0);
+ }
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ printf("DONE\n");
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+// CHECK-NOT: FAIL to vfork
+// CHECK: DONE
diff --git a/test/tsan/virtual_inheritance_compile_bug.cc b/test/tsan/virtual_inheritance_compile_bug.cc
new file mode 100644
index 000000000000..2a50c2e88d01
--- /dev/null
+++ b/test/tsan/virtual_inheritance_compile_bug.cc
@@ -0,0 +1,15 @@
+// Regression test for http://code.google.com/p/thread-sanitizer/issues/detail?id=3.
+// The C++ variant is much more compact that the LLVM IR equivalent.
+
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <stdio.h>
+struct AAA { virtual long aaa () { return 0; } }; // NOLINT
+struct BBB: virtual AAA { unsigned long bbb; }; // NOLINT
+struct CCC: virtual AAA { };
+struct DDD: CCC, BBB { DDD(); }; // NOLINT
+DDD::DDD() { }
+int main() {
+ DDD d;
+ printf("OK\n");
+}
+// CHECK: OK
diff --git a/test/tsan/vptr_benign_race.cc b/test/tsan/vptr_benign_race.cc
new file mode 100644
index 000000000000..92a2b326e717
--- /dev/null
+++ b/test/tsan/vptr_benign_race.cc
@@ -0,0 +1,51 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdio.h>
+
+struct A {
+ A() {
+ sem_init(&sem_, 0, 0);
+ }
+ virtual void F() {
+ }
+ void Done() {
+ sem_post(&sem_);
+ }
+ virtual ~A() {
+ }
+ sem_t sem_;
+};
+
+struct B : A {
+ virtual void F() {
+ }
+ virtual ~B() {
+ sem_wait(&sem_);
+ sem_destroy(&sem_);
+ }
+};
+
+static A *obj = new B;
+
+void *Thread1(void *x) {
+ obj->F();
+ obj->Done();
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ delete obj;
+ return NULL;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+ fprintf(stderr, "PASS\n");
+}
+// CHECK: PASS
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
diff --git a/test/tsan/vptr_harmful_race.cc b/test/tsan/vptr_harmful_race.cc
new file mode 100644
index 000000000000..68e12e8e7e89
--- /dev/null
+++ b/test/tsan/vptr_harmful_race.cc
@@ -0,0 +1,51 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <unistd.h>
+
+struct A {
+ A() {
+ sem_init(&sem_, 0, 0);
+ }
+ virtual void F() {
+ }
+ void Done() {
+ sem_post(&sem_);
+ }
+ virtual ~A() {
+ sem_wait(&sem_);
+ sem_destroy(&sem_);
+ }
+ sem_t sem_;
+};
+
+struct B : A {
+ virtual void F() {
+ }
+ virtual ~B() { }
+};
+
+static A *obj = new B;
+
+void *Thread1(void *x) {
+ obj->F();
+ obj->Done();
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ sleep(1);
+ delete obj;
+ return NULL;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race on vptr
diff --git a/test/tsan/vptr_harmful_race2.cc b/test/tsan/vptr_harmful_race2.cc
new file mode 100644
index 000000000000..aa53bbb90fcf
--- /dev/null
+++ b/test/tsan/vptr_harmful_race2.cc
@@ -0,0 +1,51 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <unistd.h>
+
+struct A {
+ A() {
+ sem_init(&sem_, 0, 0);
+ }
+ virtual void F() {
+ }
+ void Done() {
+ sem_post(&sem_);
+ }
+ virtual ~A() {
+ sem_wait(&sem_);
+ sem_destroy(&sem_);
+ }
+ sem_t sem_;
+};
+
+struct B : A {
+ virtual void F() {
+ }
+ virtual ~B() { }
+};
+
+static A *obj = new B;
+
+void *Thread1(void *x) {
+ sleep(1);
+ obj->F();
+ obj->Done();
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ delete obj;
+ return NULL;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race on vptr
diff --git a/test/tsan/vptr_harmful_race3.cc b/test/tsan/vptr_harmful_race3.cc
new file mode 100644
index 000000000000..ac6ea94e51eb
--- /dev/null
+++ b/test/tsan/vptr_harmful_race3.cc
@@ -0,0 +1,53 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <unistd.h>
+
+struct A {
+ A() {
+ sem_init(&sem_, 0, 0);
+ }
+ virtual void F() {
+ }
+ void Done() {
+ sem_post(&sem_);
+ }
+ virtual ~A() {
+ sem_wait(&sem_);
+ sem_destroy(&sem_);
+ }
+ sem_t sem_;
+};
+
+struct B : A {
+ virtual void F() {
+ }
+ virtual ~B() { }
+};
+
+static A *obj = new B;
+static void (A::*fn)() = &A::F;
+
+void *Thread1(void *x) {
+ sleep(1);
+ (obj->*fn)();
+ obj->Done();
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ delete obj;
+ return NULL;
+}
+
+int main() {
+ pthread_t t[2];
+ pthread_create(&t[0], NULL, Thread1, NULL);
+ pthread_create(&t[1], NULL, Thread2, NULL);
+ pthread_join(t[0], NULL);
+ pthread_join(t[1], NULL);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race on vptr
+
diff --git a/test/tsan/vptr_harmful_race4.cc b/test/tsan/vptr_harmful_race4.cc
new file mode 100644
index 000000000000..969c9d58a016
--- /dev/null
+++ b/test/tsan/vptr_harmful_race4.cc
@@ -0,0 +1,34 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+struct A {
+ virtual void F() {
+ }
+
+ virtual ~A() {
+ }
+};
+
+struct B : A {
+ virtual void F() {
+ }
+};
+
+void *Thread(void *x) {
+ sleep(1);
+ ((A*)x)->F();
+ return 0;
+}
+
+int main() {
+ A *obj = new B;
+ pthread_t t;
+ pthread_create(&t, 0, Thread, obj);
+ delete obj;
+ pthread_join(t, 0);
+}
+
+// CHECK: WARNING: ThreadSanitizer: heap-use-after-free (virtual call vs free)
+
diff --git a/test/tsan/write_in_reader_lock.cc b/test/tsan/write_in_reader_lock.cc
new file mode 100644
index 000000000000..55882139b153
--- /dev/null
+++ b/test/tsan/write_in_reader_lock.cc
@@ -0,0 +1,35 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
+#include <pthread.h>
+#include <unistd.h>
+
+pthread_rwlock_t rwlock;
+int GLOB;
+
+void *Thread1(void *p) {
+ (void)p;
+ pthread_rwlock_rdlock(&rwlock);
+ // Write under reader lock.
+ sleep(1);
+ GLOB++;
+ pthread_rwlock_unlock(&rwlock);
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+ pthread_rwlock_init(&rwlock, NULL);
+ pthread_rwlock_rdlock(&rwlock);
+ pthread_t t;
+ pthread_create(&t, 0, Thread1, 0);
+ volatile int x = GLOB;
+ (void)x;
+ pthread_rwlock_unlock(&rwlock);
+ pthread_join(t, 0);
+ pthread_rwlock_destroy(&rwlock);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Write of size 4 at {{.*}} by thread T1{{.*}}:
+// CHECK: #0 Thread1(void*) {{.*}}write_in_reader_lock.cc:13
+// CHECK: Previous read of size 4 at {{.*}} by main thread{{.*}}:
+// CHECK: #0 main {{.*}}write_in_reader_lock.cc:23
diff --git a/test/ubsan/CMakeLists.txt b/test/ubsan/CMakeLists.txt
new file mode 100644
index 000000000000..1c0c92903298
--- /dev/null
+++ b/test/ubsan/CMakeLists.txt
@@ -0,0 +1,25 @@
+set(UBSAN_LIT_TESTS_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+
+set(UBSAN_LIT_TEST_MODE "Standalone")
+configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/UbsanConfig/lit.site.cfg)
+set(UBSAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/UbsanConfig)
+
+if(COMPILER_RT_HAS_ASAN)
+ set(UBSAN_LIT_TEST_MODE "AddressSanitizer")
+ configure_lit_site_cfg(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/AsanConfig/lit.site.cfg)
+ list(APPEND UBSAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/AsanConfig)
+endif()
+
+set(UBSAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS})
+if(NOT COMPILER_RT_STANDALONE_BUILD)
+ list(APPEND UBSAN_TEST_DEPS ubsan asan)
+endif()
+
+add_lit_testsuite(check-ubsan "Running UndefinedBehaviorSanitizer tests"
+ ${UBSAN_TESTSUITES}
+ DEPENDS ${UBSAN_TEST_DEPS})
+set_target_properties(check-ubsan PROPERTIES FOLDER "UBSan unittests")
diff --git a/test/ubsan/TestCases/Float/cast-overflow.cpp b/test/ubsan/TestCases/Float/cast-overflow.cpp
new file mode 100644
index 000000000000..22991e0a6c55
--- /dev/null
+++ b/test/ubsan/TestCases/Float/cast-overflow.cpp
@@ -0,0 +1,134 @@
+// FIXME: run this (and other) UBSan tests in both 32- and 64-bit modes (?).
+// RUN: %clangxx -fsanitize=float-cast-overflow %s -o %t
+// RUN: %run %t _
+// RUN: %run %t 0 2>&1 | FileCheck %s --check-prefix=CHECK-0
+// RUN: %run %t 1 2>&1 | FileCheck %s --check-prefix=CHECK-1
+// RUN: %run %t 2 2>&1 | FileCheck %s --check-prefix=CHECK-2
+// RUN: %run %t 3 2>&1 | FileCheck %s --check-prefix=CHECK-3
+// RUN: %run %t 4 2>&1 | FileCheck %s --check-prefix=CHECK-4
+// RUN: %run %t 5 2>&1 | FileCheck %s --check-prefix=CHECK-5
+// RUN: %run %t 6 2>&1 | FileCheck %s --check-prefix=CHECK-6
+// FIXME: %run %t 7 2>&1 | FileCheck %s --check-prefix=CHECK-7
+// FIXME: not %run %t 8 2>&1 | FileCheck %s --check-prefix=CHECK-8
+// RUN: not %run %t 9 2>&1 | FileCheck %s --check-prefix=CHECK-9
+
+// This test assumes float and double are IEEE-754 single- and double-precision.
+// XFAIL: armv7l-unknown-linux-gnueabihf
+
+#if defined(__APPLE__)
+# include <machine/endian.h>
+# define BYTE_ORDER __DARWIN_BYTE_ORDER
+# define BIG_ENDIAN __DARWIN_BIG_ENDIAN
+# define LITTLE_ENDIAN __DARWIN_LITTLE_ENDIAN
+#elif defined(__FreeBSD__)
+# include <sys/endian.h>
+# define BYTE_ORDER _BYTE_ORDER
+# define BIG_ENDIAN _BIG_ENDIAN
+# define LITTLE_ENDIAN _LITTLE_ENDIAN
+#else
+# include <endian.h>
+# define BYTE_ORDER __BYTE_ORDER
+# define BIG_ENDIAN __BIG_ENDIAN
+# define LITTLE_ENDIAN __LITTLE_ENDIAN
+#endif // __APPLE__
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+float Inf;
+float NaN;
+
+int main(int argc, char **argv) {
+ float MaxFloatRepresentableAsInt = 0x7fffff80;
+ (int)MaxFloatRepresentableAsInt; // ok
+ (int)-MaxFloatRepresentableAsInt; // ok
+
+ float MinFloatRepresentableAsInt = -0x7fffffff - 1;
+ (int)MinFloatRepresentableAsInt; // ok
+
+ float MaxFloatRepresentableAsUInt = 0xffffff00u;
+ (unsigned int)MaxFloatRepresentableAsUInt; // ok
+
+#ifdef __SIZEOF_INT128__
+ unsigned __int128 FloatMaxAsUInt128 = -((unsigned __int128)1 << 104);
+ (void)(float)FloatMaxAsUInt128; // ok
+#endif
+
+ float NearlyMinusOne = -0.99999;
+ unsigned Zero = NearlyMinusOne; // ok
+
+ // Build a '+Inf'.
+#if BYTE_ORDER == LITTLE_ENDIAN
+ char InfVal[] = { 0x00, 0x00, 0x80, 0x7f };
+#else
+ char InfVal[] = { 0x7f, 0x80, 0x00, 0x00 };
+#endif
+ float Inf;
+ memcpy(&Inf, InfVal, 4);
+
+ // Build a 'NaN'.
+#if BYTE_ORDER == LITTLE_ENDIAN
+ char NaNVal[] = { 0x01, 0x00, 0x80, 0x7f };
+#else
+ char NaNVal[] = { 0x7f, 0x80, 0x00, 0x01 };
+#endif
+ float NaN;
+ memcpy(&NaN, NaNVal, 4);
+
+ double DblInf = (double)Inf; // ok
+
+ switch (argv[1][0]) {
+ // FIXME: Produce a source location for these checks and test for it here.
+
+ // Floating point -> integer overflow.
+ case '0':
+ // Note that values between 0x7ffffe00 and 0x80000000 may or may not
+ // successfully round-trip, depending on the rounding mode.
+ // CHECK-0: runtime error: value 2.14748{{.*}} is outside the range of representable values of type 'int'
+ return MaxFloatRepresentableAsInt + 0x80;
+ case '1':
+ // CHECK-1: runtime error: value -2.14748{{.*}} is outside the range of representable values of type 'int'
+ return MinFloatRepresentableAsInt - 0x100;
+ case '2': {
+ // CHECK-2: runtime error: value -1 is outside the range of representable values of type 'unsigned int'
+ volatile float f = -1.0;
+ volatile unsigned u = (unsigned)f;
+ return 0;
+ }
+ case '3':
+ // CHECK-3: runtime error: value 4.2949{{.*}} is outside the range of representable values of type 'unsigned int'
+ return (unsigned)(MaxFloatRepresentableAsUInt + 0x100);
+
+ case '4':
+ // CHECK-4: runtime error: value {{.*}} is outside the range of representable values of type 'int'
+ return Inf;
+ case '5':
+ // CHECK-5: runtime error: value {{.*}} is outside the range of representable values of type 'int'
+ return NaN;
+
+ // Integer -> floating point overflow.
+ case '6':
+ // CHECK-6: {{runtime error: value 0xffffff00000000000000000000000001 is outside the range of representable values of type 'float'|__int128 not supported}}
+#ifdef __SIZEOF_INT128__
+ return (float)(FloatMaxAsUInt128 + 1);
+#else
+ puts("__int128 not supported");
+ return 0;
+#endif
+ // FIXME: The backend cannot lower __fp16 operations on x86 yet.
+ //case '7':
+ // (__fp16)65504; // ok
+ // // CHECK-7: runtime error: value 65505 is outside the range of representable values of type '__fp16'
+ // return (__fp16)65505;
+
+ // Floating point -> floating point overflow.
+ case '8':
+ // CHECK-8: runtime error: value 1e+39 is outside the range of representable values of type 'float'
+ return (float)1e39;
+ case '9':
+ volatile long double ld = 300.0;
+ // CHECK-9: runtime error: value 300 is outside the range of representable values of type 'char'
+ char c = ld;
+ return c;
+ }
+}
diff --git a/test/ubsan/TestCases/Integer/add-overflow.cpp b/test/ubsan/TestCases/Integer/add-overflow.cpp
new file mode 100644
index 000000000000..d3425828ec88
--- /dev/null
+++ b/test/ubsan/TestCases/Integer/add-overflow.cpp
@@ -0,0 +1,32 @@
+// RUN: %clangxx -DADD_I32 -fsanitize=signed-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-ADD_I32
+// RUN: %clangxx -DADD_I64 -fsanitize=signed-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-ADD_I64
+// RUN: %clangxx -DADD_I128 -fsanitize=signed-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-ADD_I128
+
+#include <stdint.h>
+#include <stdio.h>
+
+int main() {
+ // These promote to 'int'.
+ (void)(int8_t(0x7f) + int8_t(0x7f));
+ (void)(int16_t(0x3fff) + int16_t(0x4000));
+
+#ifdef ADD_I32
+ int32_t k = 0x12345678;
+ k += 0x789abcde;
+ // CHECK-ADD_I32: add-overflow.cpp:[[@LINE-1]]:5: runtime error: signed integer overflow: 305419896 + 2023406814 cannot be represented in type 'int'
+#endif
+
+#ifdef ADD_I64
+ (void)(int64_t(8000000000000000000ll) + int64_t(2000000000000000000ll));
+ // CHECK-ADD_I64: 8000000000000000000 + 2000000000000000000 cannot be represented in type '{{long( long)?}}'
+#endif
+
+#ifdef ADD_I128
+# ifdef __SIZEOF_INT128__
+ (void)((__int128_t(1) << 126) + (__int128_t(1) << 126));
+# else
+ puts("__int128 not supported");
+# endif
+ // CHECK-ADD_I128: {{0x40000000000000000000000000000000 \+ 0x40000000000000000000000000000000 cannot be represented in type '__int128'|__int128 not supported}}
+#endif
+}
diff --git a/test/ubsan/TestCases/Integer/div-overflow.cpp b/test/ubsan/TestCases/Integer/div-overflow.cpp
new file mode 100644
index 000000000000..76dd60de45ce
--- /dev/null
+++ b/test/ubsan/TestCases/Integer/div-overflow.cpp
@@ -0,0 +1,10 @@
+// RUN: %clangxx -fsanitize=signed-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <stdint.h>
+
+int main() {
+ unsigned(0x80000000) / -1;
+
+ // CHECK: div-overflow.cpp:9:23: runtime error: division of -2147483648 by -1 cannot be represented in type 'int'
+ int32_t(0x80000000) / -1;
+}
diff --git a/test/ubsan/TestCases/Integer/div-zero.cpp b/test/ubsan/TestCases/Integer/div-zero.cpp
new file mode 100644
index 000000000000..9a223312e8e7
--- /dev/null
+++ b/test/ubsan/TestCases/Integer/div-zero.cpp
@@ -0,0 +1,15 @@
+// RUN: %clangxx -fsanitize=integer-divide-by-zero -DDIVIDEND=0 %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx -fsanitize=integer-divide-by-zero -DDIVIDEND=1U %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx -fsanitize=float-divide-by-zero -DDIVIDEND=1.5 %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx -fsanitize=integer-divide-by-zero -DDIVIDEND='intmax(123)' %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#ifdef __SIZEOF_INT128__
+typedef __int128 intmax;
+#else
+typedef long long intmax;
+#endif
+
+int main() {
+ // CHECK: div-zero.cpp:[[@LINE+1]]:12: runtime error: division by zero
+ DIVIDEND / 0;
+}
diff --git a/test/ubsan/TestCases/Integer/incdec-overflow.cpp b/test/ubsan/TestCases/Integer/incdec-overflow.cpp
new file mode 100644
index 000000000000..fc7141c803d8
--- /dev/null
+++ b/test/ubsan/TestCases/Integer/incdec-overflow.cpp
@@ -0,0 +1,16 @@
+// RUN: %clangxx -DOP=n++ -fsanitize=signed-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx -DOP=++n -fsanitize=signed-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx -DOP=m-- -fsanitize=signed-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx -DOP=--m -fsanitize=signed-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <stdint.h>
+
+int main() {
+ int n = 0x7ffffffd;
+ n++;
+ n++;
+ int m = -n - 1;
+ // CHECK: incdec-overflow.cpp:15:3: runtime error: signed integer overflow: [[MINUS:-?]]214748364
+ // CHECK: + [[MINUS]]1 cannot be represented in type 'int'
+ OP;
+}
diff --git a/test/ubsan/TestCases/Integer/mul-overflow.cpp b/test/ubsan/TestCases/Integer/mul-overflow.cpp
new file mode 100644
index 000000000000..20fece5f9fe2
--- /dev/null
+++ b/test/ubsan/TestCases/Integer/mul-overflow.cpp
@@ -0,0 +1,14 @@
+// RUN: %clangxx -fsanitize=signed-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <stdint.h>
+
+int main() {
+ // These promote to 'int'.
+ (void)(int8_t(-2) * int8_t(0x7f));
+ (void)(int16_t(0x7fff) * int16_t(0x7fff));
+ (void)(uint16_t(0xffff) * int16_t(0x7fff));
+ (void)(uint16_t(0xffff) * uint16_t(0x8000));
+
+ // CHECK: mul-overflow.cpp:13:27: runtime error: signed integer overflow: 65535 * 32769 cannot be represented in type 'int'
+ (void)(uint16_t(0xffff) * uint16_t(0x8001));
+}
diff --git a/test/ubsan/TestCases/Integer/negate-overflow.cpp b/test/ubsan/TestCases/Integer/negate-overflow.cpp
new file mode 100644
index 000000000000..bde0bdabb292
--- /dev/null
+++ b/test/ubsan/TestCases/Integer/negate-overflow.cpp
@@ -0,0 +1,12 @@
+// RUN: %clangxx -fsanitize=signed-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECKS
+// RUN: %clangxx -fsanitize=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECKU
+
+int main() {
+ // CHECKS-NOT: runtime error
+ // CHECKU: negate-overflow.cpp:[[@LINE+2]]:3: runtime error: negation of 2147483648 cannot be represented in type 'unsigned int'
+ // CHECKU-NOT: cast to an unsigned
+ -unsigned(-0x7fffffff - 1); // ok
+ // CHECKS: negate-overflow.cpp:[[@LINE+2]]:10: runtime error: negation of -2147483648 cannot be represented in type 'int'; cast to an unsigned type to negate this value to itself
+ // CHECKU-NOT: runtime error
+ return -(-0x7fffffff - 1);
+}
diff --git a/test/ubsan/TestCases/Integer/no-recover.cpp b/test/ubsan/TestCases/Integer/no-recover.cpp
new file mode 100644
index 000000000000..575bd0a553fb
--- /dev/null
+++ b/test/ubsan/TestCases/Integer/no-recover.cpp
@@ -0,0 +1,22 @@
+// RUN: %clangxx -fsanitize=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=RECOVER
+// RUN: %clangxx -fsanitize=unsigned-integer-overflow -fsanitize-recover %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=RECOVER
+// RUN: %clangxx -fsanitize=unsigned-integer-overflow -fno-sanitize-recover %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=ABORT
+
+#include <stdint.h>
+
+int main() {
+ // These promote to 'int'.
+ (void)(uint8_t(0xff) + uint8_t(0xff));
+ (void)(uint16_t(0xf0fff) + uint16_t(0x0fff));
+ // RECOVER-NOT: runtime error
+ // ABORT-NOT: runtime error
+
+ uint32_t k = 0x87654321;
+ k += 0xedcba987;
+ // RECOVER: no-recover.cpp:[[@LINE-1]]:5: runtime error: unsigned integer overflow: 2271560481 + 3989547399 cannot be represented in type 'unsigned int'
+ // ABORT: no-recover.cpp:[[@LINE-2]]:5: runtime error: unsigned integer overflow: 2271560481 + 3989547399 cannot be represented in type 'unsigned int'
+
+ (void)(uint64_t(10000000000000000000ull) + uint64_t(9000000000000000000ull));
+ // RECOVER: 10000000000000000000 + 9000000000000000000 cannot be represented in type 'unsigned {{long( long)?}}'
+ // ABORT-NOT: runtime error
+}
diff --git a/test/ubsan/TestCases/Integer/shift.cpp b/test/ubsan/TestCases/Integer/shift.cpp
new file mode 100644
index 000000000000..e86fac8d574a
--- /dev/null
+++ b/test/ubsan/TestCases/Integer/shift.cpp
@@ -0,0 +1,37 @@
+// RUN: %clangxx -DLSH_OVERFLOW -DOP='<<' -fsanitize=shift %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-LSH_OVERFLOW
+// RUN: %clangxx -DLSH_OVERFLOW -DOP='<<=' -fsanitize=shift %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-LSH_OVERFLOW
+// RUN: %clangxx -DTOO_LOW -DOP='<<' -fsanitize=shift %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_LOW
+// RUN: %clangxx -DTOO_LOW -DOP='>>' -fsanitize=shift %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_LOW
+// RUN: %clangxx -DTOO_LOW -DOP='<<=' -fsanitize=shift %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_LOW
+// RUN: %clangxx -DTOO_LOW -DOP='>>=' -fsanitize=shift %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_LOW
+// RUN: %clangxx -DTOO_HIGH -DOP='<<' -fsanitize=shift %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_HIGH
+// RUN: %clangxx -DTOO_HIGH -DOP='>>' -fsanitize=shift %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_HIGH
+// RUN: %clangxx -DTOO_HIGH -DOP='<<=' -fsanitize=shift %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_HIGH
+// RUN: %clangxx -DTOO_HIGH -DOP='>>=' -fsanitize=shift %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_HIGH
+
+#include <stdint.h>
+
+int main() {
+ int a = 1;
+ unsigned b = 1;
+
+ a <<= 31; // ok in C++11, not ok in C99/C11
+ b <<= 31; // ok
+ b <<= 1; // still ok, unsigned
+
+#ifdef LSH_OVERFLOW
+ // CHECK-LSH_OVERFLOW: shift.cpp:24:5: runtime error: left shift of negative value -2147483648
+ a OP 1;
+#endif
+
+#ifdef TOO_LOW
+ // CHECK-TOO_LOW: shift.cpp:29:5: runtime error: shift exponent -3 is negative
+ a OP (-3);
+#endif
+
+#ifdef TOO_HIGH
+ a = 0;
+ // CHECK-TOO_HIGH: shift.cpp:35:5: runtime error: shift exponent 32 is too large for 32-bit type 'int'
+ a OP 32;
+#endif
+}
diff --git a/test/ubsan/TestCases/Integer/sub-overflow.cpp b/test/ubsan/TestCases/Integer/sub-overflow.cpp
new file mode 100644
index 000000000000..15e64d951603
--- /dev/null
+++ b/test/ubsan/TestCases/Integer/sub-overflow.cpp
@@ -0,0 +1,31 @@
+// RUN: %clangxx -DSUB_I32 -fsanitize=signed-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-SUB_I32
+// RUN: %clangxx -DSUB_I64 -fsanitize=signed-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-SUB_I64
+// RUN: %clangxx -DSUB_I128 -fsanitize=signed-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-SUB_I128
+
+#include <stdint.h>
+#include <stdio.h>
+
+int main() {
+ // These promote to 'int'.
+ (void)(int8_t(-2) - int8_t(0x7f));
+ (void)(int16_t(-2) - int16_t(0x7fff));
+
+#ifdef SUB_I32
+ (void)(int32_t(-2) - int32_t(0x7fffffff));
+ // CHECK-SUB_I32: sub-overflow.cpp:[[@LINE-1]]:22: runtime error: signed integer overflow: -2 - 2147483647 cannot be represented in type 'int'
+#endif
+
+#ifdef SUB_I64
+ (void)(int64_t(-8000000000000000000ll) - int64_t(2000000000000000000ll));
+ // CHECK-SUB_I64: -8000000000000000000 - 2000000000000000000 cannot be represented in type '{{long( long)?}}'
+#endif
+
+#ifdef SUB_I128
+# ifdef __SIZEOF_INT128__
+ (void)(-(__int128_t(1) << 126) - (__int128_t(1) << 126) - 1);
+# else
+ puts("__int128 not supported");
+# endif
+ // CHECK-SUB_I128: {{0x80000000000000000000000000000000 - 1 cannot be represented in type '__int128'|__int128 not supported}}
+#endif
+}
diff --git a/test/ubsan/TestCases/Integer/summary.cpp b/test/ubsan/TestCases/Integer/summary.cpp
new file mode 100644
index 000000000000..6e9aec63ca74
--- /dev/null
+++ b/test/ubsan/TestCases/Integer/summary.cpp
@@ -0,0 +1,10 @@
+// RUN: %clangxx -fsanitize=integer %s -o %t && %t 2>&1 | FileCheck %s
+// REQUIRES: ubsan-asan
+
+#include <stdint.h>
+
+int main() {
+ (void)(uint64_t(10000000000000000000ull) + uint64_t(9000000000000000000ull));
+ // CHECK: SUMMARY: AddressSanitizer: undefined-behavior {{.*}}summary.cpp:[[@LINE-1]]
+ return 0;
+}
diff --git a/test/ubsan/TestCases/Integer/uadd-overflow.cpp b/test/ubsan/TestCases/Integer/uadd-overflow.cpp
new file mode 100644
index 000000000000..7a96880fe636
--- /dev/null
+++ b/test/ubsan/TestCases/Integer/uadd-overflow.cpp
@@ -0,0 +1,32 @@
+// RUN: %clangxx -DADD_I32 -fsanitize=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-ADD_I32
+// RUN: %clangxx -DADD_I64 -fsanitize=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-ADD_I64
+// RUN: %clangxx -DADD_I128 -fsanitize=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-ADD_I128
+
+#include <stdint.h>
+#include <stdio.h>
+
+int main() {
+ // These promote to 'int'.
+ (void)(uint8_t(0xff) + uint8_t(0xff));
+ (void)(uint16_t(0xf0fff) + uint16_t(0x0fff));
+
+#ifdef ADD_I32
+ uint32_t k = 0x87654321;
+ k += 0xedcba987;
+ // CHECK-ADD_I32: uadd-overflow.cpp:[[@LINE-1]]:5: runtime error: unsigned integer overflow: 2271560481 + 3989547399 cannot be represented in type 'unsigned int'
+#endif
+
+#ifdef ADD_I64
+ (void)(uint64_t(10000000000000000000ull) + uint64_t(9000000000000000000ull));
+ // CHECK-ADD_I64: 10000000000000000000 + 9000000000000000000 cannot be represented in type 'unsigned {{long( long)?}}'
+#endif
+
+#ifdef ADD_I128
+# ifdef __SIZEOF_INT128__
+ (void)((__uint128_t(1) << 127) + (__uint128_t(1) << 127));
+# else
+ puts("__int128 not supported");
+# endif
+ // CHECK-ADD_I128: {{0x80000000000000000000000000000000 \+ 0x80000000000000000000000000000000 cannot be represented in type 'unsigned __int128'|__int128 not supported}}
+#endif
+}
diff --git a/test/ubsan/TestCases/Integer/uincdec-overflow.cpp b/test/ubsan/TestCases/Integer/uincdec-overflow.cpp
new file mode 100644
index 000000000000..a236d21fcf1f
--- /dev/null
+++ b/test/ubsan/TestCases/Integer/uincdec-overflow.cpp
@@ -0,0 +1,16 @@
+// RUN: %clangxx -DOP=n++ -fsanitize=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck --check-prefix=CHECK-INC %s
+// RUN: %clangxx -DOP=++n -fsanitize=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck --check-prefix=CHECK-INC %s
+// RUN: %clangxx -DOP=m-- -fsanitize=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck --check-prefix=CHECK-DEC %s
+// RUN: %clangxx -DOP=--m -fsanitize=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck --check-prefix=CHECK-DEC %s
+
+#include <stdint.h>
+
+int main() {
+ unsigned n = 0xfffffffd;
+ n++;
+ n++;
+ unsigned m = 0;
+ // CHECK-INC: uincdec-overflow.cpp:15:3: runtime error: unsigned integer overflow: 4294967295 + 1 cannot be represented in type 'unsigned int'
+ // CHECK-DEC: uincdec-overflow.cpp:15:3: runtime error: unsigned integer overflow: 0 - 1 cannot be represented in type 'unsigned int'
+ OP;
+}
diff --git a/test/ubsan/TestCases/Integer/umul-overflow.cpp b/test/ubsan/TestCases/Integer/umul-overflow.cpp
new file mode 100644
index 000000000000..ad5d1bd0d13c
--- /dev/null
+++ b/test/ubsan/TestCases/Integer/umul-overflow.cpp
@@ -0,0 +1,19 @@
+// RUN: %clangxx -fsanitize=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <stdint.h>
+
+int main() {
+ // These promote to 'int'.
+ (void)(int8_t(-2) * int8_t(0x7f));
+ (void)(int16_t(0x7fff) * int16_t(0x7fff));
+ (void)(uint16_t(0xffff) * int16_t(0x7fff));
+ (void)(uint16_t(0xffff) * uint16_t(0x8000));
+
+ // Not an unsigned overflow
+ (void)(uint16_t(0xffff) * uint16_t(0x8001));
+
+ (void)(uint32_t(0xffffffff) * uint32_t(0x2));
+ // CHECK: umul-overflow.cpp:15:31: runtime error: unsigned integer overflow: 4294967295 * 2 cannot be represented in type 'unsigned int'
+
+ return 0;
+}
diff --git a/test/ubsan/TestCases/Integer/usub-overflow.cpp b/test/ubsan/TestCases/Integer/usub-overflow.cpp
new file mode 100644
index 000000000000..e5de7de54eaa
--- /dev/null
+++ b/test/ubsan/TestCases/Integer/usub-overflow.cpp
@@ -0,0 +1,31 @@
+// RUN: %clangxx -DSUB_I32 -fsanitize=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-SUB_I32
+// RUN: %clangxx -DSUB_I64 -fsanitize=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-SUB_I64
+// RUN: %clangxx -DSUB_I128 -fsanitize=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-SUB_I128
+
+#include <stdint.h>
+#include <stdio.h>
+
+int main() {
+ // These promote to 'int'.
+ (void)(uint8_t(0) - uint8_t(0x7f));
+ (void)(uint16_t(0) - uint16_t(0x7fff));
+
+#ifdef SUB_I32
+ (void)(uint32_t(1) - uint32_t(2));
+ // CHECK-SUB_I32: usub-overflow.cpp:[[@LINE-1]]:22: runtime error: unsigned integer overflow: 1 - 2 cannot be represented in type 'unsigned int'
+#endif
+
+#ifdef SUB_I64
+ (void)(uint64_t(8000000000000000000ll) - uint64_t(9000000000000000000ll));
+ // CHECK-SUB_I64: 8000000000000000000 - 9000000000000000000 cannot be represented in type 'unsigned {{long( long)?}}'
+#endif
+
+#ifdef SUB_I128
+# ifdef __SIZEOF_INT128__
+ (void)((__uint128_t(1) << 126) - (__uint128_t(1) << 127));
+# else
+ puts("__int128 not supported\n");
+# endif
+ // CHECK-SUB_I128: {{0x40000000000000000000000000000000 - 0x80000000000000000000000000000000 cannot be represented in type 'unsigned __int128'|__int128 not supported}}
+#endif
+}
diff --git a/test/ubsan/TestCases/Misc/bool.cpp b/test/ubsan/TestCases/Misc/bool.cpp
new file mode 100644
index 000000000000..37ecea27c941
--- /dev/null
+++ b/test/ubsan/TestCases/Misc/bool.cpp
@@ -0,0 +1,10 @@
+// RUN: %clangxx -fsanitize=bool %s -O3 -o %t && not %run %t 2>&1 | FileCheck %s
+
+unsigned char NotABool = 123;
+
+int main(int argc, char **argv) {
+ bool *p = (bool*)&NotABool;
+
+ // CHECK: bool.cpp:9:10: runtime error: load of value 123, which is not a valid value for type 'bool'
+ return *p;
+}
diff --git a/test/ubsan/TestCases/Misc/bounds.cpp b/test/ubsan/TestCases/Misc/bounds.cpp
new file mode 100644
index 000000000000..ffcac528be90
--- /dev/null
+++ b/test/ubsan/TestCases/Misc/bounds.cpp
@@ -0,0 +1,15 @@
+// RUN: %clangxx -fsanitize=bounds %s -O3 -o %t
+// RUN: %run %t 0 0 0
+// RUN: %run %t 1 2 3
+// RUN: not --crash %run %t 2 0 0 2>&1 | FileCheck %s --check-prefix=CHECK-A-2
+// RUN: %run %t 0 3 0 2>&1 | FileCheck %s --check-prefix=CHECK-B-3
+// RUN: %run %t 0 0 4 2>&1 | FileCheck %s --check-prefix=CHECK-C-4
+
+int main(int argc, char **argv) {
+ int arr[2][3][4] = {};
+
+ return arr[argv[1][0] - '0'][argv[2][0] - '0'][argv[3][0] - '0'];
+ // CHECK-A-2: bounds.cpp:[[@LINE-1]]:10: runtime error: index 2 out of bounds for type 'int [2][3][4]'
+ // CHECK-B-3: bounds.cpp:[[@LINE-2]]:10: runtime error: index 3 out of bounds for type 'int [3][4]'
+ // CHECK-C-4: bounds.cpp:[[@LINE-3]]:10: runtime error: index 4 out of bounds for type 'int [4]'
+}
diff --git a/test/ubsan/TestCases/Misc/deduplication.cpp b/test/ubsan/TestCases/Misc/deduplication.cpp
new file mode 100644
index 000000000000..7d7b0bd58c6e
--- /dev/null
+++ b/test/ubsan/TestCases/Misc/deduplication.cpp
@@ -0,0 +1,25 @@
+// RUN: %clangxx -fsanitize=undefined %s -o %t && %run %t 2>&1 | FileCheck %s
+// Verify deduplication works by ensuring only one diag is emitted.
+#include <limits.h>
+#include <stdio.h>
+
+void overflow() {
+ int i = INT_MIN;
+ --i;
+}
+
+int main() {
+ // CHECK: Start
+ fprintf(stderr, "Start\n");
+
+ // CHECK: runtime error
+ // CHECK-NOT: runtime error
+ // CHECK-NOT: runtime error
+ overflow();
+ overflow();
+ overflow();
+
+ // CHECK: End
+ fprintf(stderr, "End\n");
+ return 0;
+}
diff --git a/test/ubsan/TestCases/Misc/enum.cpp b/test/ubsan/TestCases/Misc/enum.cpp
new file mode 100644
index 000000000000..49ac7c6bb187
--- /dev/null
+++ b/test/ubsan/TestCases/Misc/enum.cpp
@@ -0,0 +1,17 @@
+// RUN: %clangxx -fsanitize=enum %s -O3 -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-PLAIN
+// RUN: %clangxx -fsanitize=enum -std=c++11 -DE="class E" %s -O3 -o %t && %run %t
+// RUN: %clangxx -fsanitize=enum -std=c++11 -DE="class E : bool" %s -O3 -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-BOOL
+
+enum E { a = 1 } e;
+#undef E
+
+int main(int argc, char **argv) {
+ // memset(&e, 0xff, sizeof(e));
+ for (unsigned char *p = (unsigned char*)&e; p != (unsigned char*)(&e + 1); ++p)
+ *p = 0xff;
+
+ // CHECK-PLAIN: error: load of value 4294967295, which is not a valid value for type 'enum E'
+ // FIXME: Support marshalling and display of enum class values.
+ // CHECK-BOOL: error: load of value <unknown>, which is not a valid value for type 'enum E'
+ return (int)e != -1;
+}
diff --git a/test/ubsan/TestCases/Misc/missing_return.cpp b/test/ubsan/TestCases/Misc/missing_return.cpp
new file mode 100644
index 000000000000..5d3d54de17dd
--- /dev/null
+++ b/test/ubsan/TestCases/Misc/missing_return.cpp
@@ -0,0 +1,17 @@
+// RUN: %clangxx -fsanitize=return -g %s -O3 -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: UBSAN_OPTIONS=print_stacktrace=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os-STACKTRACE
+
+// CHECK: missing_return.cpp:[[@LINE+1]]:5: runtime error: execution reached the end of a value-returning function without returning a value
+int f() {
+// Slow stack unwinding is disabled on Darwin for now, see
+// https://code.google.com/p/address-sanitizer/issues/detail?id=137
+// CHECK-Linux-STACKTRACE: #0 {{.*}} in f(){{.*}}missing_return.cpp:[[@LINE-3]]
+// CHECK-FreeBSD-STACKTRACE: #0 {{.*}} in f(void){{.*}}missing_return.cpp:[[@LINE-4]]
+// Check for already checked line to avoid lit error reports.
+// CHECK-Darwin-STACKTRACE: missing_return.cpp
+}
+
+int main(int, char **argv) {
+ return f();
+}
diff --git a/test/ubsan/TestCases/Misc/nonnull-arg.cpp b/test/ubsan/TestCases/Misc/nonnull-arg.cpp
new file mode 100644
index 000000000000..b1061b757899
--- /dev/null
+++ b/test/ubsan/TestCases/Misc/nonnull-arg.cpp
@@ -0,0 +1,58 @@
+// RUN: %clangxx -fsanitize=nonnull-attribute -fno-sanitize-recover %s -O3 -o %t
+// RUN: %run %t nc
+// RUN: %run %t nm
+// RUN: %run %t nf
+// RUN: %run %t nv
+// RUN: not %run %t 0c 2>&1 | FileCheck %s --check-prefix=CTOR
+// RUN: not %run %t 0m 2>&1 | FileCheck %s --check-prefix=METHOD
+// RUN: not %run %t 0f 2>&1 | FileCheck %s --check-prefix=FUNC
+// RUN: not %run %t 0v 2>&1 | FileCheck %s --check-prefix=VARIADIC
+
+class C {
+ int *null_;
+ int *nonnull_;
+
+public:
+ C(int *null, __attribute__((nonnull)) int *nonnull)
+ : null_(null), nonnull_(nonnull) {}
+ int value() { return *nonnull_; }
+ int method(int *nonnull, int *null) __attribute__((nonnull(2))) {
+ return *nonnull_ + *nonnull;
+ }
+};
+
+__attribute__((nonnull)) int func(int *nonnull) { return *nonnull; }
+
+#include <stdarg.h>
+__attribute__((nonnull)) int variadic(int x, ...) {
+ va_list args;
+ va_start(args, x);
+ int *nonnull = va_arg(args, int*);
+ int res = *nonnull;
+ va_end(args);
+ return res;
+}
+
+int main(int argc, char *argv[]) {
+ int local = 0;
+ int *arg = (argv[1][0] == '0') ? 0x0 : &local;
+ switch (argv[1][1]) {
+ case 'c':
+ return C(0x0, arg).value();
+ // CTOR: {{.*}}nonnull-arg.cpp:[[@LINE-1]]:21: runtime error: null pointer passed as argument 2, which is declared to never be null
+ // CTOR-NEXT: {{.*}}nonnull-arg.cpp:16:31: note: nonnull attribute specified here
+ case 'm':
+ return C(0x0, &local).method(arg, 0x0);
+ // METHOD: {{.*}}nonnull-arg.cpp:[[@LINE-1]]:36: runtime error: null pointer passed as argument 1, which is declared to never be null
+ // METHOD-NEXT: {{.*}}nonnull-arg.cpp:19:54: note: nonnull attribute specified here
+ case 'f':
+ return func(arg);
+ // FUNC: {{.*}}nonnull-arg.cpp:[[@LINE-1]]:19: runtime error: null pointer passed as argument 1, which is declared to never be null
+ // FUNC-NEXT: {{.*}}nonnull-arg.cpp:24:16: note: nonnull attribute specified here
+ case 'v':
+ return variadic(42, arg);
+ // VARIADIC: {{.*}}nonnull-arg.cpp:[[@LINE-1]]:27: runtime error: null pointer passed as argument 2, which is declared to never be null
+ // VARIADIC-NEXT: {{.*}}nonnull-arg.cpp:27:16: note: nonnull attribute specified here
+ }
+ return 0;
+}
diff --git a/test/ubsan/TestCases/Misc/nonnull.cpp b/test/ubsan/TestCases/Misc/nonnull.cpp
new file mode 100644
index 000000000000..c3ab49c11df7
--- /dev/null
+++ b/test/ubsan/TestCases/Misc/nonnull.cpp
@@ -0,0 +1,15 @@
+// RUN: %clangxx -fsanitize=returns-nonnull-attribute %s -O3 -o %t
+// RUN: %run %t foo
+// RUN: %run %t 2>&1 | FileCheck %s
+
+__attribute__((returns_nonnull)) char *foo(char *a);
+
+char *foo(char *a) {
+ return a;
+ // CHECK: nonnull.cpp:[[@LINE+2]]:1: runtime error: null pointer returned from function declared to never return null
+ // CHECK-NEXT: nonnull.cpp:[[@LINE-5]]:16: note: returns_nonnull attribute specified here
+}
+
+int main(int argc, char **argv) {
+ return foo(argv[1]) == 0;
+}
diff --git a/test/ubsan/TestCases/Misc/unreachable.cpp b/test/ubsan/TestCases/Misc/unreachable.cpp
new file mode 100644
index 000000000000..e1206edb30d5
--- /dev/null
+++ b/test/ubsan/TestCases/Misc/unreachable.cpp
@@ -0,0 +1,6 @@
+// RUN: %clangxx -fsanitize=unreachable %s -O3 -o %t && not %run %t 2>&1 | FileCheck %s
+
+int main(int, char **argv) {
+ // CHECK: unreachable.cpp:5:3: runtime error: execution reached a __builtin_unreachable() call
+ __builtin_unreachable();
+}
diff --git a/test/ubsan/TestCases/Misc/vla.c b/test/ubsan/TestCases/Misc/vla.c
new file mode 100644
index 000000000000..10721537bbbc
--- /dev/null
+++ b/test/ubsan/TestCases/Misc/vla.c
@@ -0,0 +1,11 @@
+// RUN: %clang -fsanitize=vla-bound %s -O3 -o %t
+// RUN: %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-MINUS-ONE
+// RUN: %run %t a 2>&1 | FileCheck %s --check-prefix=CHECK-ZERO
+// RUN: %run %t a b
+
+int main(int argc, char **argv) {
+ // CHECK-MINUS-ONE: vla.c:9:11: runtime error: variable length array bound evaluates to non-positive value -1
+ // CHECK-ZERO: vla.c:9:11: runtime error: variable length array bound evaluates to non-positive value 0
+ int arr[argc - 2];
+ return 0;
+}
diff --git a/test/ubsan/TestCases/TypeCheck/Function/function.cpp b/test/ubsan/TestCases/TypeCheck/Function/function.cpp
new file mode 100644
index 000000000000..deca77d459c0
--- /dev/null
+++ b/test/ubsan/TestCases/TypeCheck/Function/function.cpp
@@ -0,0 +1,24 @@
+// RUN: %clangxx -fsanitize=function %s -O3 -g -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+// Verify that we can disable symbolization if needed:
+// RUN: UBSAN_OPTIONS=symbolize=0 ASAN_OPTIONS=symbolize=0 %run %t 2>&1 | FileCheck %s --check-prefix=NOSYM
+
+// -fsanitize=function is unsupported on Darwin yet.
+// XFAIL: darwin
+
+#include <stdint.h>
+
+void f() {}
+
+void g(int x) {}
+
+int main(void) {
+ // CHECK: runtime error: call to function f() through pointer to incorrect function type 'void (*)(int)'
+ // CHECK-NEXT: function.cpp:11: note: f() defined here
+ // NOSYM: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int)'
+ // NOSYM-NEXT: ({{.*}}+0x{{.*}}): note: (unknown) defined here
+ reinterpret_cast<void (*)(int)>(reinterpret_cast<uintptr_t>(f))(42);
+
+ // CHECK-NOT: runtime error: call to function g
+ reinterpret_cast<void (*)(int)>(reinterpret_cast<uintptr_t>(g))(42);
+}
diff --git a/test/ubsan/TestCases/TypeCheck/Function/lit.local.cfg b/test/ubsan/TestCases/TypeCheck/Function/lit.local.cfg
new file mode 100644
index 000000000000..27c61a34387c
--- /dev/null
+++ b/test/ubsan/TestCases/TypeCheck/Function/lit.local.cfg
@@ -0,0 +1,3 @@
+# The function type checker is only supported on x86 and x86_64 for now.
+if config.root.host_arch not in ['x86', 'x86_64']:
+ config.unsupported = True
diff --git a/test/ubsan/TestCases/TypeCheck/misaligned.cpp b/test/ubsan/TestCases/TypeCheck/misaligned.cpp
new file mode 100644
index 000000000000..79f5136db963
--- /dev/null
+++ b/test/ubsan/TestCases/TypeCheck/misaligned.cpp
@@ -0,0 +1,105 @@
+// RUN: %clangxx -fsanitize=alignment -g %s -O3 -o %t
+// RUN: %run %t l0 && %run %t s0 && %run %t r0 && %run %t m0 && %run %t f0 && %run %t n0 && %run %t u0
+// RUN: %run %t l1 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD --strict-whitespace
+// RUN: %run %t s1 2>&1 | FileCheck %s --check-prefix=CHECK-STORE
+// RUN: %run %t r1 2>&1 | FileCheck %s --check-prefix=CHECK-REFERENCE
+// RUN: %run %t m1 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER
+// RUN: %run %t f1 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN
+// RUN: %run %t n1 2>&1 | FileCheck %s --check-prefix=CHECK-NEW
+// RUN: %run %t u1 2>&1 | FileCheck %s --check-prefix=CHECK-UPCAST
+// RUN: UBSAN_OPTIONS=print_stacktrace=1 %run %t l1 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD --check-prefix=CHECK-%os-STACK-LOAD
+
+// RUN: %clangxx -fsanitize=alignment -fno-sanitize-recover %s -O3 -o %t
+// RUN: not %run %t w1 2>&1 | FileCheck %s --check-prefix=CHECK-WILD
+// XFAIL: armv7l-unknown-linux-gnueabihf
+
+#include <new>
+
+struct S {
+ S() {}
+ int f() { return 0; }
+ int k;
+};
+
+struct T : S {
+ int t;
+};
+
+int main(int, char **argv) {
+ char c[] __attribute__((aligned(8))) = { 0, 0, 0, 0, 1, 2, 3, 4, 5 };
+
+ // Pointer value may be unspecified here, but behavior is not undefined.
+ int *p = (int*)&c[4 + argv[1][1] - '0'];
+ S *s = (S*)p;
+ T *t = (T*)p;
+
+ void *wild = reinterpret_cast<void *>(0x123L);
+
+ (void)*p; // ok!
+
+ switch (argv[1][0]) {
+ case 'l':
+ // CHECK-LOAD: misaligned.cpp:[[@LINE+4]]:12: runtime error: load of misaligned address [[PTR:0x[0-9a-f]*]] for type 'int', which requires 4 byte alignment
+ // CHECK-LOAD-NEXT: [[PTR]]: note: pointer points here
+ // CHECK-LOAD-NEXT: {{^ 00 00 00 01 02 03 04 05}}
+ // CHECK-LOAD-NEXT: {{^ \^}}
+ return *p && 0;
+ // Slow stack unwinding is disabled on Darwin for now, see
+ // https://code.google.com/p/address-sanitizer/issues/detail?id=137
+ // CHECK-Linux-STACK-LOAD: #0 {{.*}} in main{{.*}}misaligned.cpp
+ // Check for the already checked line to avoid lit error reports.
+ // CHECK-Darwin-STACK-LOAD: {{ }}
+
+ case 's':
+ // CHECK-STORE: misaligned.cpp:[[@LINE+4]]:5: runtime error: store to misaligned address [[PTR:0x[0-9a-f]*]] for type 'int', which requires 4 byte alignment
+ // CHECK-STORE-NEXT: [[PTR]]: note: pointer points here
+ // CHECK-STORE-NEXT: {{^ 00 00 00 01 02 03 04 05}}
+ // CHECK-STORE-NEXT: {{^ \^}}
+ *p = 1;
+ break;
+
+ case 'r':
+ // CHECK-REFERENCE: misaligned.cpp:[[@LINE+4]]:15: runtime error: reference binding to misaligned address [[PTR:0x[0-9a-f]*]] for type 'int', which requires 4 byte alignment
+ // CHECK-REFERENCE-NEXT: [[PTR]]: note: pointer points here
+ // CHECK-REFERENCE-NEXT: {{^ 00 00 00 01 02 03 04 05}}
+ // CHECK-REFERENCE-NEXT: {{^ \^}}
+ {int &r = *p;}
+ break;
+
+ case 'm':
+ // CHECK-MEMBER: misaligned.cpp:[[@LINE+4]]:15: runtime error: member access within misaligned address [[PTR:0x[0-9a-f]*]] for type 'S', which requires 4 byte alignment
+ // CHECK-MEMBER-NEXT: [[PTR]]: note: pointer points here
+ // CHECK-MEMBER-NEXT: {{^ 00 00 00 01 02 03 04 05}}
+ // CHECK-MEMBER-NEXT: {{^ \^}}
+ return s->k && 0;
+
+ case 'f':
+ // CHECK-MEMFUN: misaligned.cpp:[[@LINE+4]]:12: runtime error: member call on misaligned address [[PTR:0x[0-9a-f]*]] for type 'S', which requires 4 byte alignment
+ // CHECK-MEMFUN-NEXT: [[PTR]]: note: pointer points here
+ // CHECK-MEMFUN-NEXT: {{^ 00 00 00 01 02 03 04 05}}
+ // CHECK-MEMFUN-NEXT: {{^ \^}}
+ return s->f() && 0;
+
+ case 'n':
+ // CHECK-NEW: misaligned.cpp:[[@LINE+4]]:5: runtime error: constructor call on misaligned address [[PTR:0x[0-9a-f]*]] for type 'S', which requires 4 byte alignment
+ // CHECK-NEW-NEXT: [[PTR]]: note: pointer points here
+ // CHECK-NEW-NEXT: {{^ 00 00 00 01 02 03 04 05}}
+ // CHECK-NEW-NEXT: {{^ \^}}
+ return (new (s) S)->k && 0;
+
+ case 'u': {
+ // CHECK-UPCAST: misaligned.cpp:[[@LINE+4]]:17: runtime error: upcast of misaligned address [[PTR:0x[0-9a-f]*]] for type 'T', which requires 4 byte alignment
+ // CHECK-UPCAST-NEXT: [[PTR]]: note: pointer points here
+ // CHECK-UPCAST-NEXT: {{^ 00 00 00 01 02 03 04 05}}
+ // CHECK-UPCAST-NEXT: {{^ \^}}
+ S *s2 = (S*)t;
+ return s2->f();
+ }
+
+ case 'w':
+ // CHECK-WILD: misaligned.cpp:[[@LINE+3]]:35: runtime error: member access within misaligned address 0x000000000123 for type 'S', which requires 4 byte alignment
+ // CHECK-WILD-NEXT: 0x000000000123: note: pointer points here
+ // CHECK-WILD-NEXT: <memory cannot be printed>
+ return static_cast<S*>(wild)->k;
+ }
+}
diff --git a/test/ubsan/TestCases/TypeCheck/null.cpp b/test/ubsan/TestCases/TypeCheck/null.cpp
new file mode 100644
index 000000000000..2a90f7fb956b
--- /dev/null
+++ b/test/ubsan/TestCases/TypeCheck/null.cpp
@@ -0,0 +1,38 @@
+// RUN: %clangxx -fsanitize=null %s -O3 -o %t
+// RUN: %run %t l 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD
+// RUN: not --crash %run %t s 2>&1 | FileCheck %s --check-prefix=CHECK-STORE
+// RUN: %run %t r 2>&1 | FileCheck %s --check-prefix=CHECK-REFERENCE
+// RUN: %run %t m 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER
+// RUN: %run %t f 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN
+
+struct S {
+ int f() { return 0; }
+ int k;
+};
+
+int main(int, char **argv) {
+ int *p = 0;
+ S *s = 0;
+
+ (void)*p; // ok!
+
+ switch (argv[1][0]) {
+ case 'l':
+ // CHECK-LOAD: null.cpp:22:12: runtime error: load of null pointer of type 'int'
+ return *p;
+ case 's':
+ // CHECK-STORE: null.cpp:25:5: runtime error: store to null pointer of type 'int'
+ *p = 1;
+ break;
+ case 'r':
+ // CHECK-REFERENCE: null.cpp:29:15: runtime error: reference binding to null pointer of type 'int'
+ {int &r = *p;}
+ break;
+ case 'm':
+ // CHECK-MEMBER: null.cpp:33:15: runtime error: member access within null pointer of type 'S'
+ return s->k;
+ case 'f':
+ // CHECK-MEMFUN: null.cpp:36:12: runtime error: member call on null pointer of type 'S'
+ return s->f();
+ }
+}
diff --git a/test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp b/test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp
new file mode 100644
index 000000000000..5261e71c2d3d
--- /dev/null
+++ b/test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp
@@ -0,0 +1,19 @@
+// RUN: %clangxx -fsanitize=vptr -fno-sanitize-recover -g %s -O3 -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+// FIXME: This test produces linker errors on Darwin.
+// XFAIL: darwin
+
+struct S { virtual int f() { return 0; } };
+struct T : virtual S {};
+
+struct Foo { virtual int f() { return 0; } };
+
+int main(int argc, char **argv) {
+ Foo foo;
+ T *t = (T*)&foo;
+ S *s = t;
+ // CHECK: vptr-virtual-base.cpp:[[@LINE-1]]:10: runtime error: cast to virtual base of address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
+ // CHECK-NEXT: [[PTR]]: note: object is of type 'Foo'
+ return s->f();
+}
diff --git a/test/ubsan/TestCases/TypeCheck/vptr.cpp b/test/ubsan/TestCases/TypeCheck/vptr.cpp
new file mode 100644
index 000000000000..3a6b1553f9b3
--- /dev/null
+++ b/test/ubsan/TestCases/TypeCheck/vptr.cpp
@@ -0,0 +1,166 @@
+// RUN: %clangxx -fsanitize=vptr -g %s -O3 -o %t
+// RUN: %run %t rT && %run %t mT && %run %t fT && %run %t cT
+// RUN: %run %t rU && %run %t mU && %run %t fU && %run %t cU
+// RUN: %run %t rS && %run %t rV && %run %t oV
+// RUN: %run %t mS 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER --strict-whitespace
+// RUN: %run %t fS 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN --strict-whitespace
+// RUN: %run %t cS 2>&1 | FileCheck %s --check-prefix=CHECK-DOWNCAST --strict-whitespace
+// RUN: %run %t mV 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER --strict-whitespace
+// RUN: %run %t fV 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN --strict-whitespace
+// RUN: %run %t cV 2>&1 | FileCheck %s --check-prefix=CHECK-DOWNCAST --strict-whitespace
+// RUN: %run %t oU 2>&1 | FileCheck %s --check-prefix=CHECK-OFFSET --strict-whitespace
+// RUN: %run %t m0 2>&1 | FileCheck %s --check-prefix=CHECK-NULL-MEMBER --strict-whitespace
+
+// RUN: (echo "vptr_check:S"; echo "vptr_check:T"; echo "vptr_check:U") > %t.supp
+// RUN: ASAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 %run %t mS 2>&1
+// RUN: ASAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 %run %t fS 2>&1
+// RUN: ASAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 %run %t cS 2>&1
+// RUN: ASAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 %run %t mV 2>&1
+// RUN: ASAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 %run %t fV 2>&1
+// RUN: ASAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 %run %t cV 2>&1
+// RUN: ASAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 %run %t oU 2>&1
+
+// RUN: echo "vptr_check:S" > %t.loc-supp
+// RUN: ASAN_OPTIONS=suppressions=%t.loc-supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.loc-supp:halt_on_error=1 not %run %t x- 2>&1 | FileCheck %s --check-prefix=CHECK-LOC-SUPPRESS
+
+// FIXME: This test produces linker errors on Darwin.
+// XFAIL: darwin
+// REQUIRES: stable-runtime
+
+extern "C" {
+const char *__ubsan_default_options() {
+ return "print_stacktrace=1";
+}
+}
+
+struct S {
+ S() : a(0) {}
+ ~S() {}
+ int a;
+ int f() { return 0; }
+ virtual int v() { return 0; }
+};
+
+struct T : S {
+ T() : b(0) {}
+ int b;
+ int g() { return 0; }
+ virtual int v() { return 1; }
+};
+
+struct X {};
+struct U : S, T, virtual X { virtual int v() { return 2; } };
+
+struct V : S {};
+
+// Make p global so that lsan does not complain.
+T *p = 0;
+
+int access_p(T *p, char type);
+
+int main(int, char **argv) {
+ T t;
+ (void)t.a;
+ (void)t.b;
+ (void)t.f();
+ (void)t.g();
+ (void)t.v();
+ (void)t.S::v();
+
+ U u;
+ (void)u.T::a;
+ (void)u.b;
+ (void)u.T::f();
+ (void)u.g();
+ (void)u.v();
+ (void)u.T::v();
+ (void)((T&)u).S::v();
+
+ char Buffer[sizeof(U)] = {};
+ switch (argv[1][1]) {
+ case '0':
+ p = reinterpret_cast<T*>(Buffer);
+ break;
+ case 'S':
+ p = reinterpret_cast<T*>(new S);
+ break;
+ case 'T':
+ p = new T;
+ break;
+ case 'U':
+ p = new U;
+ break;
+ case 'V':
+ p = reinterpret_cast<T*>(new U);
+ break;
+ }
+
+ access_p(p, argv[1][0]);
+ return 0;
+}
+
+int access_p(T *p, char type) {
+ switch (type) {
+ case 'r':
+ // Binding a reference to storage of appropriate size and alignment is OK.
+ {T &r = *p;}
+ break;
+
+ case 'x':
+ for (int i = 0; i < 2; i++) {
+ // Check that the first iteration ("S") succeeds, while the second ("V") fails.
+ p = reinterpret_cast<T*>((i == 0) ? new S : new V);
+ // CHECK-LOC-SUPPRESS: vptr.cpp:[[@LINE+5]]:7: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
+ // CHECK-LOC-SUPPRESS-NEXT: [[PTR]]: note: object is of type 'V'
+ // CHECK-LOC-SUPPRESS-NEXT: {{^ .. .. .. .. .. .. .. .. .. .. .. .. }}
+ // CHECK-LOC-SUPPRESS-NEXT: {{^ \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
+ // CHECK-LOC-SUPPRESS-NEXT: {{^ vptr for 'V'}}
+ p->g();
+ }
+ return 0;
+
+ case 'm':
+ // CHECK-MEMBER: vptr.cpp:[[@LINE+6]]:15: runtime error: member access within address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
+ // CHECK-MEMBER-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
+ // CHECK-MEMBER-NEXT: {{^ .. .. .. .. .. .. .. .. .. .. .. .. }}
+ // CHECK-MEMBER-NEXT: {{^ \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
+ // CHECK-MEMBER-NEXT: {{^ vptr for}} [[DYN_TYPE]]
+ // CHECK-MEMBER-NEXT: #0 {{.*}} in access_p{{.*}}vptr.cpp:[[@LINE+1]]
+ return p->b;
+
+ // CHECK-NULL-MEMBER: vptr.cpp:[[@LINE-2]]:15: runtime error: member access within address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
+ // CHECK-NULL-MEMBER-NEXT: [[PTR]]: note: object has invalid vptr
+ // CHECK-NULL-MEMBER-NEXT: {{^ ?.. .. .. .. ?00 00 00 00 ?00 00 00 00 ?}}
+ // CHECK-NULL-MEMBER-NEXT: {{^ \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
+ // CHECK-NULL-MEMBER-NEXT: {{^ invalid vptr}}
+ // CHECK-NULL-MEMBER-NEXT: #0 {{.*}} in access_p{{.*}}vptr.cpp:[[@LINE-7]]
+
+ case 'f':
+ // CHECK-MEMFUN: vptr.cpp:[[@LINE+6]]:12: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
+ // CHECK-MEMFUN-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
+ // CHECK-MEMFUN-NEXT: {{^ .. .. .. .. .. .. .. .. .. .. .. .. }}
+ // CHECK-MEMFUN-NEXT: {{^ \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
+ // CHECK-MEMFUN-NEXT: {{^ vptr for}} [[DYN_TYPE]]
+ // TODO: Add check for stacktrace here.
+ return p->g();
+
+ case 'o':
+ // CHECK-OFFSET: vptr.cpp:[[@LINE+6]]:12: runtime error: member call on address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'U'
+ // CHECK-OFFSET-NEXT: 0x{{[0-9a-f]*}}: note: object is base class subobject at offset {{8|16}} within object of type [[DYN_TYPE:'U']]
+ // CHECK-OFFSET-NEXT: {{^ .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. }}
+ // CHECK-OFFSET-NEXT: {{^ \^ ( ~~~~~~~~~~~~)?~~~~~~~~~~~ *$}}
+ // CHECK-OFFSET-NEXT: {{^ ( )?vptr for}} 'T' base class of [[DYN_TYPE]]
+ // CHECK-OFFSET-NEXT: #0 {{.*}} in access_p{{.*}}vptr.cpp:[[@LINE+1]]
+ return reinterpret_cast<U*>(p)->v() - 2;
+
+ case 'c':
+ // CHECK-DOWNCAST: vptr.cpp:[[@LINE+6]]:5: runtime error: downcast of address [[PTR:0x[0-9a-f]*]] which does not point to an object of type 'T'
+ // CHECK-DOWNCAST-NEXT: [[PTR]]: note: object is of type [[DYN_TYPE:'S'|'U']]
+ // CHECK-DOWNCAST-NEXT: {{^ .. .. .. .. .. .. .. .. .. .. .. .. }}
+ // CHECK-DOWNCAST-NEXT: {{^ \^~~~~~~~~~~(~~~~~~~~~~~~)? *$}}
+ // CHECK-DOWNCAST-NEXT: {{^ vptr for}} [[DYN_TYPE]]
+ // CHECK-DOWNCAST-NEXT: #0 {{.*}} in access_p{{.*}}vptr.cpp:[[@LINE+1]]
+ static_cast<T*>(reinterpret_cast<S*>(p));
+ return 0;
+ }
+}
diff --git a/test/ubsan/lit.common.cfg b/test/ubsan/lit.common.cfg
new file mode 100644
index 000000000000..d28733a61cf8
--- /dev/null
+++ b/test/ubsan/lit.common.cfg
@@ -0,0 +1,56 @@
+# -*- Python -*-
+
+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 source root.
+config.test_source_root = os.path.dirname(__file__)
+
+# Choose between standalone and UBSan+ASan modes.
+ubsan_lit_test_mode = get_required_attr(config, 'ubsan_lit_test_mode')
+if ubsan_lit_test_mode == "Standalone":
+ config.name = 'UndefinedBehaviorSanitizer-Standalone'
+ config.available_features.add("ubsan-standalone")
+ clang_ubsan_cflags = []
+elif ubsan_lit_test_mode == "AddressSanitizer":
+ if config.host_os == 'Darwin':
+ # ubsan-asan doesn't yet work on Darwin,
+ # see http://llvm.org/bugs/show_bug.cgi?id=21112.
+ config.unsupported = True
+ config.name = 'UndefinedBehaviorSanitizer-AddressSanitizer'
+ config.available_features.add("ubsan-asan")
+ clang_ubsan_cflags = ["-fsanitize=address"]
+ config.environment['ASAN_OPTIONS'] = 'detect_leaks=0'
+else:
+ lit_config.fatal("Unknown UBSan test mode: %r" % ubsan_lit_test_mode)
+
+def build_invocation(compile_flags):
+ return " " + " ".join([config.clang] + compile_flags) + " "
+
+target_cflags = [get_required_attr(config, "target_cflags")]
+clang_ubsan_cflags += target_cflags
+clang_ubsan_cxxflags = config.cxx_mode_flags + clang_ubsan_cflags
+
+# Define %clang and %clangxx substitutions to use in test RUN lines.
+config.substitutions.append( ("%clang ", build_invocation(clang_ubsan_cflags)) )
+config.substitutions.append( ("%clangxx ", build_invocation(clang_ubsan_cxxflags)) )
+
+# Default test suffixes.
+config.suffixes = ['.c', '.cc', '.cpp']
+
+# Check that the host supports UndefinedBehaviorSanitizer tests
+if config.host_os not in ['Linux', 'Darwin', 'FreeBSD']:
+ config.unsupported = True
+
+# Allow tests to use REQUIRES=stable-runtime. For use when you cannot use XFAIL
+# because the test hangs or fails on one configuration and not the other.
+if config.target_arch.startswith('arm') == False:
+ config.available_features.add('stable-runtime')
diff --git a/test/ubsan/lit.site.cfg.in b/test/ubsan/lit.site.cfg.in
new file mode 100644
index 000000000000..ef72d2bbb42f
--- /dev/null
+++ b/test/ubsan/lit.site.cfg.in
@@ -0,0 +1,8 @@
+# Load common config for all compiler-rt lit tests.
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")
+
+# Tool-specific config options.
+config.ubsan_lit_test_mode = "@UBSAN_LIT_TEST_MODE@"
+
+# Load tool-specific config that would do the real work.
+lit_config.load_config(config, "@UBSAN_LIT_TESTS_DIR@/lit.common.cfg")