From 8ef50bf3d1c287b5013c3168de77a462dfce3495 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Thu, 6 Nov 2014 22:49:13 +0000 Subject: Import compiler-rt release_34 branch r197381. https://llvm.org/svn/llvm-project/compiler-rt/branches/release_34@197381 --- lib/asan/CMakeLists.txt | 116 +++- lib/asan/asan.syms | 5 - lib/asan/asan.syms.extra | 3 + lib/asan/asan_allocator.h | 11 +- lib/asan/asan_allocator2.cc | 246 ++++---- lib/asan/asan_blacklist.txt | 4 +- lib/asan/asan_dll_thunk.cc | 196 +++++++ lib/asan/asan_fake_stack.cc | 295 +++++----- lib/asan/asan_fake_stack.h | 196 ++++--- lib/asan/asan_flags.h | 20 +- lib/asan/asan_globals.cc | 8 +- lib/asan/asan_intercepted_functions.h | 35 -- lib/asan/asan_interceptors.cc | 219 +++---- lib/asan/asan_interface_internal.h | 129 ++--- lib/asan/asan_internal.h | 1 + lib/asan/asan_linux.cc | 11 + lib/asan/asan_mac.cc | 28 +- lib/asan/asan_mac.h | 12 +- lib/asan/asan_malloc_linux.cc | 5 +- lib/asan/asan_malloc_mac.cc | 12 +- lib/asan/asan_malloc_win.cc | 16 +- lib/asan/asan_mapping.h | 34 +- lib/asan/asan_poisoning.cc | 63 +- lib/asan/asan_poisoning.h | 4 +- lib/asan/asan_posix.cc | 15 +- lib/asan/asan_report.cc | 196 ++++--- lib/asan/asan_report.h | 6 +- lib/asan/asan_rtl.cc | 125 ++-- lib/asan/asan_stack.cc | 9 +- lib/asan/asan_stack.h | 29 +- lib/asan/asan_stats.cc | 126 ++-- lib/asan/asan_stats.h | 12 +- lib/asan/asan_thread.cc | 139 ++++- lib/asan/asan_thread.h | 70 ++- lib/asan/asan_win.cc | 11 + lib/asan/lit_tests/32bitConfig/lit.site.cfg.in | 13 + lib/asan/lit_tests/64bitConfig/lit.site.cfg.in | 12 + lib/asan/lit_tests/CMakeLists.txt | 28 +- .../lit_tests/Darwin/interface_symbols_darwin.c | 39 -- lib/asan/lit_tests/Darwin/lit.local.cfg | 9 - .../Darwin/reexec-insert-libraries-env.cc | 20 - .../Darwin/unset-insert-libraries-on-exec.cc | 20 - lib/asan/lit_tests/Helpers/blacklist-extra.cc | 5 - .../lit_tests/Helpers/init-order-atexit-extra.cc | 16 - .../Helpers/initialization-blacklist-extra.cc | 15 - .../Helpers/initialization-blacklist-extra2.cc | 4 - .../lit_tests/Helpers/initialization-blacklist.txt | 3 - .../lit_tests/Helpers/initialization-bug-extra.cc | 5 - .../lit_tests/Helpers/initialization-bug-extra2.cc | 6 - .../Helpers/initialization-constexpr-extra.cc | 3 - .../Helpers/initialization-nobug-extra.cc | 9 - lib/asan/lit_tests/Helpers/lit.local.cfg | 3 - lib/asan/lit_tests/Linux/asan_prelink_test.cc | 28 - lib/asan/lit_tests/Linux/clone_test.cc | 48 -- lib/asan/lit_tests/Linux/glob.cc | 30 - lib/asan/lit_tests/Linux/glob_test_root/aa | 0 lib/asan/lit_tests/Linux/glob_test_root/ab | 0 lib/asan/lit_tests/Linux/glob_test_root/ba | 0 lib/asan/lit_tests/Linux/heavy_uar_test.cc | 55 -- .../Linux/initialization-bug-any-order.cc | 38 -- .../lit_tests/Linux/interception_failure_test.cc | 26 - .../lit_tests/Linux/interception_malloc_test.cc | 27 - lib/asan/lit_tests/Linux/interception_test.cc | 26 - lib/asan/lit_tests/Linux/interface_symbols_linux.c | 34 -- lib/asan/lit_tests/Linux/lit.local.cfg | 9 - lib/asan/lit_tests/Linux/malloc-in-qsort.cc | 54 -- lib/asan/lit_tests/Linux/malloc_delete_mismatch.cc | 26 - lib/asan/lit_tests/Linux/overflow-in-qsort.cc | 51 -- lib/asan/lit_tests/Linux/preinit_test.cc | 27 - lib/asan/lit_tests/Linux/rlimit_mmap_test.cc | 16 - lib/asan/lit_tests/Linux/swapcontext_test.cc | 94 --- lib/asan/lit_tests/Linux/syscalls.cc | 22 - lib/asan/lit_tests/Linux/time_null_regtest.cc | 20 - lib/asan/lit_tests/Linux/zero-base-shadow.cc | 31 - .../SharedLibs/darwin-dummy-shared-lib-so.cc | 13 - lib/asan/lit_tests/SharedLibs/dlclose-test-so.cc | 33 -- .../lit_tests/SharedLibs/init-order-dlopen-so.cc | 12 - lib/asan/lit_tests/SharedLibs/lit.local.cfg | 4 - .../lit_tests/SharedLibs/shared-lib-test-so.cc | 21 - .../TestCases/Darwin/interface_symbols_darwin.c | 41 ++ lib/asan/lit_tests/TestCases/Darwin/lit.local.cfg | 9 + .../Darwin/malloc_set_zone_name-mprotect.cc | 51 ++ .../TestCases/Darwin/malloc_zone-protected.cc | 20 + .../Darwin/reexec-insert-libraries-env.cc | 20 + .../Darwin/unset-insert-libraries-on-exec.cc | 20 + .../lit_tests/TestCases/Helpers/blacklist-extra.cc | 5 + lib/asan/lit_tests/TestCases/Helpers/echo-env.cc | 19 + .../TestCases/Helpers/init-order-atexit-extra.cc | 16 + .../Helpers/init-order-pthread-create-extra.cc | 2 + .../Helpers/initialization-blacklist-extra.cc | 15 + .../Helpers/initialization-blacklist-extra2.cc | 4 + .../TestCases/Helpers/initialization-blacklist.txt | 3 + .../TestCases/Helpers/initialization-bug-extra.cc | 5 + .../TestCases/Helpers/initialization-bug-extra2.cc | 6 + .../Helpers/initialization-constexpr-extra.cc | 3 + .../Helpers/initialization-nobug-extra.cc | 9 + lib/asan/lit_tests/TestCases/Helpers/lit.local.cfg | 3 + .../lit_tests/TestCases/Linux/asan_prelink_test.cc | 28 + lib/asan/lit_tests/TestCases/Linux/clone_test.cc | 44 ++ lib/asan/lit_tests/TestCases/Linux/coverage.cc | 45 ++ lib/asan/lit_tests/TestCases/Linux/glob.cc | 29 + .../lit_tests/TestCases/Linux/glob_test_root/aa | 0 .../lit_tests/TestCases/Linux/glob_test_root/ab | 0 .../lit_tests/TestCases/Linux/glob_test_root/ba | 0 .../TestCases/Linux/heap-overflow-large.cc | 23 + .../lit_tests/TestCases/Linux/heavy_uar_test.cc | 54 ++ .../Linux/initialization-bug-any-order.cc | 36 ++ .../TestCases/Linux/interception_failure_test.cc | 22 + .../TestCases/Linux/interception_malloc_test.cc | 23 + .../TestCases/Linux/interception_readdir_r_test.cc | 59 ++ .../lit_tests/TestCases/Linux/interception_test.cc | 22 + .../TestCases/Linux/interface_symbols_linux.c | 35 ++ lib/asan/lit_tests/TestCases/Linux/lit.local.cfg | 9 + .../lit_tests/TestCases/Linux/malloc-in-qsort.cc | 56 ++ .../TestCases/Linux/malloc_delete_mismatch.cc | 31 + .../lit_tests/TestCases/Linux/overflow-in-qsort.cc | 51 ++ lib/asan/lit_tests/TestCases/Linux/preinit_test.cc | 27 + lib/asan/lit_tests/TestCases/Linux/ptrace.cc | 52 ++ .../lit_tests/TestCases/Linux/rlimit_mmap_test.cc | 16 + .../lit_tests/TestCases/Linux/swapcontext_test.cc | 90 +++ lib/asan/lit_tests/TestCases/Linux/syscalls.cc | 22 + .../lit_tests/TestCases/Linux/time_null_regtest.cc | 20 + .../lit_tests/TestCases/Linux/tsd_dtor_leak.cc | 39 ++ lib/asan/lit_tests/TestCases/Linux/uar_signals.cc | 70 +++ lib/asan/lit_tests/TestCases/Linux/unpoison_tls.cc | 35 ++ .../TestCases/Linux/zero-base-shadow32.cc | 24 + .../TestCases/Linux/zero-base-shadow64.cc | 24 + .../SharedLibs/darwin-dummy-shared-lib-so.cc | 13 + .../TestCases/SharedLibs/dlclose-test-so.cc | 33 ++ .../TestCases/SharedLibs/init-order-dlopen-so.cc | 12 + .../lit_tests/TestCases/SharedLibs/lit.local.cfg | 4 + .../TestCases/SharedLibs/shared-lib-test-so.cc | 26 + .../lit_tests/TestCases/allocator_returns_null.cc | 81 +++ lib/asan/lit_tests/TestCases/allow_user_segv.cc | 48 ++ .../TestCases/asan-symbolize-sanity-test.cc | 39 ++ .../TestCases/assign_large_valloc_to_global.cc | 8 + lib/asan/lit_tests/TestCases/atexit_stats.cc | 13 + lib/asan/lit_tests/TestCases/blacklist.cc | 38 ++ .../lit_tests/TestCases/contiguous_container.cc | 47 ++ .../lit_tests/TestCases/current_allocated_bytes.cc | 43 ++ lib/asan/lit_tests/TestCases/deep_call_stack.cc | 25 + lib/asan/lit_tests/TestCases/deep_stack_uaf.cc | 31 + lib/asan/lit_tests/TestCases/deep_tail_call.cc | 20 + lib/asan/lit_tests/TestCases/deep_thread_stack.cc | 57 ++ lib/asan/lit_tests/TestCases/default_blacklist.cc | 3 + lib/asan/lit_tests/TestCases/default_options.cc | 15 + lib/asan/lit_tests/TestCases/dlclose-test.cc | 81 +++ lib/asan/lit_tests/TestCases/double-free.cc | 25 + lib/asan/lit_tests/TestCases/force_inline_opt0.cc | 14 + lib/asan/lit_tests/TestCases/free_hook_realloc.cc | 32 + lib/asan/lit_tests/TestCases/global-demangle.cc | 17 + lib/asan/lit_tests/TestCases/global-overflow.cc | 21 + lib/asan/lit_tests/TestCases/heap-overflow.cc | 24 + .../lit_tests/TestCases/huge_negative_hea_oob.cc | 13 + lib/asan/lit_tests/TestCases/init-order-atexit.cc | 31 + lib/asan/lit_tests/TestCases/init-order-dlopen.cc | 57 ++ .../TestCases/init-order-pthread-create.cc | 32 + .../TestCases/initialization-blacklist.cc | 32 + lib/asan/lit_tests/TestCases/initialization-bug.cc | 45 ++ .../TestCases/initialization-constexpr.cc | 31 + .../lit_tests/TestCases/initialization-nobug.cc | 48 ++ lib/asan/lit_tests/TestCases/inline.cc | 19 + lib/asan/lit_tests/TestCases/interface_test.cc | 8 + lib/asan/lit_tests/TestCases/invalid-free.cc | 21 + lib/asan/lit_tests/TestCases/ioctl.cc | 24 + lib/asan/lit_tests/TestCases/large_func_test.cc | 51 ++ lib/asan/lit_tests/TestCases/log-path_test.cc | 39 ++ .../TestCases/log_path_fork_test.cc.disabled | 22 + lib/asan/lit_tests/TestCases/lsan_annotations.cc | 16 + .../lit_tests/TestCases/malloc_context_size.cc | 27 + lib/asan/lit_tests/TestCases/malloc_fill.cc | 22 + lib/asan/lit_tests/TestCases/malloc_hook.cc | 36 ++ lib/asan/lit_tests/TestCases/memcmp_strict_test.cc | 15 + lib/asan/lit_tests/TestCases/memcmp_test.cc | 17 + lib/asan/lit_tests/TestCases/null_deref.cc | 19 + lib/asan/lit_tests/TestCases/on_error_callback.cc | 16 + lib/asan/lit_tests/TestCases/partial_right.cc | 13 + lib/asan/lit_tests/TestCases/poison_partial.cc | 19 + lib/asan/lit_tests/TestCases/print_summary.cc | 14 + lib/asan/lit_tests/TestCases/readv.cc | 32 + lib/asan/lit_tests/TestCases/sanity_check_pure_c.c | 19 + lib/asan/lit_tests/TestCases/shared-lib-test.cc | 42 ++ lib/asan/lit_tests/TestCases/sleep_before_dying.c | 10 + .../stack-buffer-overflow-with-position.cc | 45 ++ .../lit_tests/TestCases/stack-frame-demangle.cc | 22 + lib/asan/lit_tests/TestCases/stack-oob-frames.cc | 59 ++ lib/asan/lit_tests/TestCases/stack-overflow.cc | 16 + .../lit_tests/TestCases/stack-use-after-return.cc | 77 +++ lib/asan/lit_tests/TestCases/strdup_oob_test.cc | 19 + lib/asan/lit_tests/TestCases/strerror_r_test.cc | 13 + lib/asan/lit_tests/TestCases/strip_path_prefix.c | 12 + lib/asan/lit_tests/TestCases/strncpy-overflow.cc | 28 + lib/asan/lit_tests/TestCases/symbolize_callback.cc | 17 + lib/asan/lit_tests/TestCases/throw_call_test.cc | 45 ++ lib/asan/lit_tests/TestCases/throw_invoke_test.cc | 50 ++ lib/asan/lit_tests/TestCases/time_interceptor.cc | 16 + lib/asan/lit_tests/TestCases/uar_and_exceptions.cc | 40 ++ .../TestCases/unaligned_loads_and_stores.cc | 52 ++ .../lit_tests/TestCases/use-after-free-right.cc | 34 ++ lib/asan/lit_tests/TestCases/use-after-free.cc | 31 + lib/asan/lit_tests/TestCases/use-after-poison.cc | 20 + .../TestCases/use-after-scope-dtor-order.cc | 25 + .../lit_tests/TestCases/use-after-scope-inlined.cc | 27 + .../lit_tests/TestCases/use-after-scope-nobug.cc | 14 + .../lit_tests/TestCases/use-after-scope-temp.cc | 29 + lib/asan/lit_tests/TestCases/use-after-scope.cc | 16 + lib/asan/lit_tests/TestCases/wait.cc | 63 ++ lib/asan/lit_tests/Unit/lit.cfg | 26 - lib/asan/lit_tests/Unit/lit.site.cfg.in | 23 +- lib/asan/lit_tests/allow_user_segv.cc | 50 -- lib/asan/lit_tests/blacklist.cc | 44 -- lib/asan/lit_tests/deep_stack_uaf.cc | 36 -- lib/asan/lit_tests/deep_tail_call.cc | 24 - lib/asan/lit_tests/deep_thread_stack.cc | 61 -- lib/asan/lit_tests/default_blacklist.cc | 3 - lib/asan/lit_tests/default_options.cc | 15 - lib/asan/lit_tests/dlclose-test.cc | 93 --- lib/asan/lit_tests/double-free.cc | 18 - lib/asan/lit_tests/force_inline_opt0.cc | 14 - lib/asan/lit_tests/global-demangle.cc | 18 - lib/asan/lit_tests/global-overflow.cc | 25 - lib/asan/lit_tests/heap-overflow.cc | 36 -- lib/asan/lit_tests/huge_negative_hea_oob.cc | 13 - lib/asan/lit_tests/init-order-atexit.cc | 31 - lib/asan/lit_tests/init-order-dlopen.cc | 52 -- lib/asan/lit_tests/initialization-blacklist.cc | 47 -- lib/asan/lit_tests/initialization-bug.cc | 49 -- lib/asan/lit_tests/initialization-constexpr.cc | 43 -- lib/asan/lit_tests/initialization-nobug.cc | 56 -- lib/asan/lit_tests/interface_test.cc | 8 - lib/asan/lit_tests/invalid-free.cc | 16 - lib/asan/lit_tests/large_func_test.cc | 63 -- lib/asan/lit_tests/lit.cfg | 83 ++- lib/asan/lit_tests/lit.site.cfg.in | 22 - lib/asan/lit_tests/log-path_test.cc | 39 -- lib/asan/lit_tests/log_path_fork_test.cc.disabled | 22 - lib/asan/lit_tests/malloc_fill.cc | 22 - lib/asan/lit_tests/malloc_hook.cc | 24 - lib/asan/lit_tests/memcmp_strict_test.cc | 16 - lib/asan/lit_tests/memcmp_test.cc | 19 - lib/asan/lit_tests/null_deref.cc | 31 - lib/asan/lit_tests/on_error_callback.cc | 16 - lib/asan/lit_tests/partial_right.cc | 17 - lib/asan/lit_tests/sanity_check_pure_c.c | 19 - lib/asan/lit_tests/shared-lib-test.cc | 54 -- lib/asan/lit_tests/sleep_before_dying.c | 10 - lib/asan/lit_tests/stack-frame-demangle.cc | 22 - lib/asan/lit_tests/stack-oob-frames.cc | 59 -- lib/asan/lit_tests/stack-overflow.cc | 20 - lib/asan/lit_tests/stack-use-after-return.cc | 45 -- lib/asan/lit_tests/strip_path_prefix.c | 12 - lib/asan/lit_tests/strncpy-overflow.cc | 38 -- lib/asan/lit_tests/symbolize_callback.cc | 17 - lib/asan/lit_tests/throw_call_test.cc | 45 -- lib/asan/lit_tests/throw_invoke_test.cc | 50 -- lib/asan/lit_tests/time_interceptor.cc | 16 - lib/asan/lit_tests/unaligned_loads_and_stores.cc | 52 -- lib/asan/lit_tests/use-after-free-right.cc | 46 -- lib/asan/lit_tests/use-after-free.cc | 43 -- lib/asan/lit_tests/use-after-poison.cc | 20 - lib/asan/lit_tests/use-after-scope-inlined.cc | 30 - lib/asan/lit_tests/wait.cc | 77 --- lib/asan/scripts/asan_symbolize.py | 63 +- lib/asan/tests/CMakeLists.txt | 167 ++++-- lib/asan/tests/asan_fake_stack_test.cc | 150 +++++ lib/asan/tests/asan_interface_test.cc | 426 ++++++++++++++ lib/asan/tests/asan_mac_test_helpers.mm | 39 +- lib/asan/tests/asan_noinst_test.cc | 645 ++------------------- lib/asan/tests/asan_str_test.cc | 16 + lib/asan/tests/asan_test.cc | 45 +- lib/asan/tests/asan_test_utils.h | 4 - 271 files changed, 6008 insertions(+), 4326 deletions(-) delete mode 100644 lib/asan/asan.syms create mode 100644 lib/asan/asan.syms.extra create mode 100644 lib/asan/asan_dll_thunk.cc create mode 100644 lib/asan/lit_tests/32bitConfig/lit.site.cfg.in create mode 100644 lib/asan/lit_tests/64bitConfig/lit.site.cfg.in delete mode 100644 lib/asan/lit_tests/Darwin/interface_symbols_darwin.c delete mode 100644 lib/asan/lit_tests/Darwin/lit.local.cfg delete mode 100644 lib/asan/lit_tests/Darwin/reexec-insert-libraries-env.cc delete mode 100644 lib/asan/lit_tests/Darwin/unset-insert-libraries-on-exec.cc delete mode 100644 lib/asan/lit_tests/Helpers/blacklist-extra.cc delete mode 100644 lib/asan/lit_tests/Helpers/init-order-atexit-extra.cc delete mode 100644 lib/asan/lit_tests/Helpers/initialization-blacklist-extra.cc delete mode 100644 lib/asan/lit_tests/Helpers/initialization-blacklist-extra2.cc delete mode 100644 lib/asan/lit_tests/Helpers/initialization-blacklist.txt delete mode 100644 lib/asan/lit_tests/Helpers/initialization-bug-extra.cc delete mode 100644 lib/asan/lit_tests/Helpers/initialization-bug-extra2.cc delete mode 100644 lib/asan/lit_tests/Helpers/initialization-constexpr-extra.cc delete mode 100644 lib/asan/lit_tests/Helpers/initialization-nobug-extra.cc delete mode 100644 lib/asan/lit_tests/Helpers/lit.local.cfg delete mode 100644 lib/asan/lit_tests/Linux/asan_prelink_test.cc delete mode 100644 lib/asan/lit_tests/Linux/clone_test.cc delete mode 100644 lib/asan/lit_tests/Linux/glob.cc delete mode 100644 lib/asan/lit_tests/Linux/glob_test_root/aa delete mode 100644 lib/asan/lit_tests/Linux/glob_test_root/ab delete mode 100644 lib/asan/lit_tests/Linux/glob_test_root/ba delete mode 100644 lib/asan/lit_tests/Linux/heavy_uar_test.cc delete mode 100644 lib/asan/lit_tests/Linux/initialization-bug-any-order.cc delete mode 100644 lib/asan/lit_tests/Linux/interception_failure_test.cc delete mode 100644 lib/asan/lit_tests/Linux/interception_malloc_test.cc delete mode 100644 lib/asan/lit_tests/Linux/interception_test.cc delete mode 100644 lib/asan/lit_tests/Linux/interface_symbols_linux.c delete mode 100644 lib/asan/lit_tests/Linux/lit.local.cfg delete mode 100644 lib/asan/lit_tests/Linux/malloc-in-qsort.cc delete mode 100644 lib/asan/lit_tests/Linux/malloc_delete_mismatch.cc delete mode 100644 lib/asan/lit_tests/Linux/overflow-in-qsort.cc delete mode 100644 lib/asan/lit_tests/Linux/preinit_test.cc delete mode 100644 lib/asan/lit_tests/Linux/rlimit_mmap_test.cc delete mode 100644 lib/asan/lit_tests/Linux/swapcontext_test.cc delete mode 100644 lib/asan/lit_tests/Linux/syscalls.cc delete mode 100644 lib/asan/lit_tests/Linux/time_null_regtest.cc delete mode 100644 lib/asan/lit_tests/Linux/zero-base-shadow.cc delete mode 100644 lib/asan/lit_tests/SharedLibs/darwin-dummy-shared-lib-so.cc delete mode 100644 lib/asan/lit_tests/SharedLibs/dlclose-test-so.cc delete mode 100644 lib/asan/lit_tests/SharedLibs/init-order-dlopen-so.cc delete mode 100644 lib/asan/lit_tests/SharedLibs/lit.local.cfg delete mode 100644 lib/asan/lit_tests/SharedLibs/shared-lib-test-so.cc create mode 100644 lib/asan/lit_tests/TestCases/Darwin/interface_symbols_darwin.c create mode 100644 lib/asan/lit_tests/TestCases/Darwin/lit.local.cfg create mode 100644 lib/asan/lit_tests/TestCases/Darwin/malloc_set_zone_name-mprotect.cc create mode 100644 lib/asan/lit_tests/TestCases/Darwin/malloc_zone-protected.cc create mode 100644 lib/asan/lit_tests/TestCases/Darwin/reexec-insert-libraries-env.cc create mode 100644 lib/asan/lit_tests/TestCases/Darwin/unset-insert-libraries-on-exec.cc create mode 100644 lib/asan/lit_tests/TestCases/Helpers/blacklist-extra.cc create mode 100644 lib/asan/lit_tests/TestCases/Helpers/echo-env.cc create mode 100644 lib/asan/lit_tests/TestCases/Helpers/init-order-atexit-extra.cc create mode 100644 lib/asan/lit_tests/TestCases/Helpers/init-order-pthread-create-extra.cc create mode 100644 lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra.cc create mode 100644 lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra2.cc create mode 100644 lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist.txt create mode 100644 lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra.cc create mode 100644 lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra2.cc create mode 100644 lib/asan/lit_tests/TestCases/Helpers/initialization-constexpr-extra.cc create mode 100644 lib/asan/lit_tests/TestCases/Helpers/initialization-nobug-extra.cc create mode 100644 lib/asan/lit_tests/TestCases/Helpers/lit.local.cfg create mode 100644 lib/asan/lit_tests/TestCases/Linux/asan_prelink_test.cc create mode 100644 lib/asan/lit_tests/TestCases/Linux/clone_test.cc create mode 100644 lib/asan/lit_tests/TestCases/Linux/coverage.cc create mode 100644 lib/asan/lit_tests/TestCases/Linux/glob.cc create mode 100644 lib/asan/lit_tests/TestCases/Linux/glob_test_root/aa create mode 100644 lib/asan/lit_tests/TestCases/Linux/glob_test_root/ab create mode 100644 lib/asan/lit_tests/TestCases/Linux/glob_test_root/ba create mode 100644 lib/asan/lit_tests/TestCases/Linux/heap-overflow-large.cc create mode 100644 lib/asan/lit_tests/TestCases/Linux/heavy_uar_test.cc create mode 100644 lib/asan/lit_tests/TestCases/Linux/initialization-bug-any-order.cc create mode 100644 lib/asan/lit_tests/TestCases/Linux/interception_failure_test.cc create mode 100644 lib/asan/lit_tests/TestCases/Linux/interception_malloc_test.cc create mode 100644 lib/asan/lit_tests/TestCases/Linux/interception_readdir_r_test.cc create mode 100644 lib/asan/lit_tests/TestCases/Linux/interception_test.cc create mode 100644 lib/asan/lit_tests/TestCases/Linux/interface_symbols_linux.c create mode 100644 lib/asan/lit_tests/TestCases/Linux/lit.local.cfg create mode 100644 lib/asan/lit_tests/TestCases/Linux/malloc-in-qsort.cc create mode 100644 lib/asan/lit_tests/TestCases/Linux/malloc_delete_mismatch.cc create mode 100644 lib/asan/lit_tests/TestCases/Linux/overflow-in-qsort.cc create mode 100644 lib/asan/lit_tests/TestCases/Linux/preinit_test.cc create mode 100644 lib/asan/lit_tests/TestCases/Linux/ptrace.cc create mode 100644 lib/asan/lit_tests/TestCases/Linux/rlimit_mmap_test.cc create mode 100644 lib/asan/lit_tests/TestCases/Linux/swapcontext_test.cc create mode 100644 lib/asan/lit_tests/TestCases/Linux/syscalls.cc create mode 100644 lib/asan/lit_tests/TestCases/Linux/time_null_regtest.cc create mode 100644 lib/asan/lit_tests/TestCases/Linux/tsd_dtor_leak.cc create mode 100644 lib/asan/lit_tests/TestCases/Linux/uar_signals.cc create mode 100644 lib/asan/lit_tests/TestCases/Linux/unpoison_tls.cc create mode 100644 lib/asan/lit_tests/TestCases/Linux/zero-base-shadow32.cc create mode 100644 lib/asan/lit_tests/TestCases/Linux/zero-base-shadow64.cc create mode 100644 lib/asan/lit_tests/TestCases/SharedLibs/darwin-dummy-shared-lib-so.cc create mode 100644 lib/asan/lit_tests/TestCases/SharedLibs/dlclose-test-so.cc create mode 100644 lib/asan/lit_tests/TestCases/SharedLibs/init-order-dlopen-so.cc create mode 100644 lib/asan/lit_tests/TestCases/SharedLibs/lit.local.cfg create mode 100644 lib/asan/lit_tests/TestCases/SharedLibs/shared-lib-test-so.cc create mode 100644 lib/asan/lit_tests/TestCases/allocator_returns_null.cc create mode 100644 lib/asan/lit_tests/TestCases/allow_user_segv.cc create mode 100644 lib/asan/lit_tests/TestCases/asan-symbolize-sanity-test.cc create mode 100644 lib/asan/lit_tests/TestCases/assign_large_valloc_to_global.cc create mode 100644 lib/asan/lit_tests/TestCases/atexit_stats.cc create mode 100644 lib/asan/lit_tests/TestCases/blacklist.cc create mode 100644 lib/asan/lit_tests/TestCases/contiguous_container.cc create mode 100644 lib/asan/lit_tests/TestCases/current_allocated_bytes.cc create mode 100644 lib/asan/lit_tests/TestCases/deep_call_stack.cc create mode 100644 lib/asan/lit_tests/TestCases/deep_stack_uaf.cc create mode 100644 lib/asan/lit_tests/TestCases/deep_tail_call.cc create mode 100644 lib/asan/lit_tests/TestCases/deep_thread_stack.cc create mode 100644 lib/asan/lit_tests/TestCases/default_blacklist.cc create mode 100644 lib/asan/lit_tests/TestCases/default_options.cc create mode 100644 lib/asan/lit_tests/TestCases/dlclose-test.cc create mode 100644 lib/asan/lit_tests/TestCases/double-free.cc create mode 100644 lib/asan/lit_tests/TestCases/force_inline_opt0.cc create mode 100644 lib/asan/lit_tests/TestCases/free_hook_realloc.cc create mode 100644 lib/asan/lit_tests/TestCases/global-demangle.cc create mode 100644 lib/asan/lit_tests/TestCases/global-overflow.cc create mode 100644 lib/asan/lit_tests/TestCases/heap-overflow.cc create mode 100644 lib/asan/lit_tests/TestCases/huge_negative_hea_oob.cc create mode 100644 lib/asan/lit_tests/TestCases/init-order-atexit.cc create mode 100644 lib/asan/lit_tests/TestCases/init-order-dlopen.cc create mode 100644 lib/asan/lit_tests/TestCases/init-order-pthread-create.cc create mode 100644 lib/asan/lit_tests/TestCases/initialization-blacklist.cc create mode 100644 lib/asan/lit_tests/TestCases/initialization-bug.cc create mode 100644 lib/asan/lit_tests/TestCases/initialization-constexpr.cc create mode 100644 lib/asan/lit_tests/TestCases/initialization-nobug.cc create mode 100644 lib/asan/lit_tests/TestCases/inline.cc create mode 100644 lib/asan/lit_tests/TestCases/interface_test.cc create mode 100644 lib/asan/lit_tests/TestCases/invalid-free.cc create mode 100644 lib/asan/lit_tests/TestCases/ioctl.cc create mode 100644 lib/asan/lit_tests/TestCases/large_func_test.cc create mode 100644 lib/asan/lit_tests/TestCases/log-path_test.cc create mode 100644 lib/asan/lit_tests/TestCases/log_path_fork_test.cc.disabled create mode 100644 lib/asan/lit_tests/TestCases/lsan_annotations.cc create mode 100644 lib/asan/lit_tests/TestCases/malloc_context_size.cc create mode 100644 lib/asan/lit_tests/TestCases/malloc_fill.cc create mode 100644 lib/asan/lit_tests/TestCases/malloc_hook.cc create mode 100644 lib/asan/lit_tests/TestCases/memcmp_strict_test.cc create mode 100644 lib/asan/lit_tests/TestCases/memcmp_test.cc create mode 100644 lib/asan/lit_tests/TestCases/null_deref.cc create mode 100644 lib/asan/lit_tests/TestCases/on_error_callback.cc create mode 100644 lib/asan/lit_tests/TestCases/partial_right.cc create mode 100644 lib/asan/lit_tests/TestCases/poison_partial.cc create mode 100644 lib/asan/lit_tests/TestCases/print_summary.cc create mode 100644 lib/asan/lit_tests/TestCases/readv.cc create mode 100644 lib/asan/lit_tests/TestCases/sanity_check_pure_c.c create mode 100644 lib/asan/lit_tests/TestCases/shared-lib-test.cc create mode 100644 lib/asan/lit_tests/TestCases/sleep_before_dying.c create mode 100644 lib/asan/lit_tests/TestCases/stack-buffer-overflow-with-position.cc create mode 100644 lib/asan/lit_tests/TestCases/stack-frame-demangle.cc create mode 100644 lib/asan/lit_tests/TestCases/stack-oob-frames.cc create mode 100644 lib/asan/lit_tests/TestCases/stack-overflow.cc create mode 100644 lib/asan/lit_tests/TestCases/stack-use-after-return.cc create mode 100644 lib/asan/lit_tests/TestCases/strdup_oob_test.cc create mode 100644 lib/asan/lit_tests/TestCases/strerror_r_test.cc create mode 100644 lib/asan/lit_tests/TestCases/strip_path_prefix.c create mode 100644 lib/asan/lit_tests/TestCases/strncpy-overflow.cc create mode 100644 lib/asan/lit_tests/TestCases/symbolize_callback.cc create mode 100644 lib/asan/lit_tests/TestCases/throw_call_test.cc create mode 100644 lib/asan/lit_tests/TestCases/throw_invoke_test.cc create mode 100644 lib/asan/lit_tests/TestCases/time_interceptor.cc create mode 100644 lib/asan/lit_tests/TestCases/uar_and_exceptions.cc create mode 100644 lib/asan/lit_tests/TestCases/unaligned_loads_and_stores.cc create mode 100644 lib/asan/lit_tests/TestCases/use-after-free-right.cc create mode 100644 lib/asan/lit_tests/TestCases/use-after-free.cc create mode 100644 lib/asan/lit_tests/TestCases/use-after-poison.cc create mode 100644 lib/asan/lit_tests/TestCases/use-after-scope-dtor-order.cc create mode 100644 lib/asan/lit_tests/TestCases/use-after-scope-inlined.cc create mode 100644 lib/asan/lit_tests/TestCases/use-after-scope-nobug.cc create mode 100644 lib/asan/lit_tests/TestCases/use-after-scope-temp.cc create mode 100644 lib/asan/lit_tests/TestCases/use-after-scope.cc create mode 100644 lib/asan/lit_tests/TestCases/wait.cc delete mode 100644 lib/asan/lit_tests/Unit/lit.cfg delete mode 100644 lib/asan/lit_tests/allow_user_segv.cc delete mode 100644 lib/asan/lit_tests/blacklist.cc delete mode 100644 lib/asan/lit_tests/deep_stack_uaf.cc delete mode 100644 lib/asan/lit_tests/deep_tail_call.cc delete mode 100644 lib/asan/lit_tests/deep_thread_stack.cc delete mode 100644 lib/asan/lit_tests/default_blacklist.cc delete mode 100644 lib/asan/lit_tests/default_options.cc delete mode 100644 lib/asan/lit_tests/dlclose-test.cc delete mode 100644 lib/asan/lit_tests/double-free.cc delete mode 100644 lib/asan/lit_tests/force_inline_opt0.cc delete mode 100644 lib/asan/lit_tests/global-demangle.cc delete mode 100644 lib/asan/lit_tests/global-overflow.cc delete mode 100644 lib/asan/lit_tests/heap-overflow.cc delete mode 100644 lib/asan/lit_tests/huge_negative_hea_oob.cc delete mode 100644 lib/asan/lit_tests/init-order-atexit.cc delete mode 100644 lib/asan/lit_tests/init-order-dlopen.cc delete mode 100644 lib/asan/lit_tests/initialization-blacklist.cc delete mode 100644 lib/asan/lit_tests/initialization-bug.cc delete mode 100644 lib/asan/lit_tests/initialization-constexpr.cc delete mode 100644 lib/asan/lit_tests/initialization-nobug.cc delete mode 100644 lib/asan/lit_tests/interface_test.cc delete mode 100644 lib/asan/lit_tests/invalid-free.cc delete mode 100644 lib/asan/lit_tests/large_func_test.cc delete mode 100644 lib/asan/lit_tests/lit.site.cfg.in delete mode 100644 lib/asan/lit_tests/log-path_test.cc delete mode 100644 lib/asan/lit_tests/log_path_fork_test.cc.disabled delete mode 100644 lib/asan/lit_tests/malloc_fill.cc delete mode 100644 lib/asan/lit_tests/malloc_hook.cc delete mode 100644 lib/asan/lit_tests/memcmp_strict_test.cc delete mode 100644 lib/asan/lit_tests/memcmp_test.cc delete mode 100644 lib/asan/lit_tests/null_deref.cc delete mode 100644 lib/asan/lit_tests/on_error_callback.cc delete mode 100644 lib/asan/lit_tests/partial_right.cc delete mode 100644 lib/asan/lit_tests/sanity_check_pure_c.c delete mode 100644 lib/asan/lit_tests/shared-lib-test.cc delete mode 100644 lib/asan/lit_tests/sleep_before_dying.c delete mode 100644 lib/asan/lit_tests/stack-frame-demangle.cc delete mode 100644 lib/asan/lit_tests/stack-oob-frames.cc delete mode 100644 lib/asan/lit_tests/stack-overflow.cc delete mode 100644 lib/asan/lit_tests/stack-use-after-return.cc delete mode 100644 lib/asan/lit_tests/strip_path_prefix.c delete mode 100644 lib/asan/lit_tests/strncpy-overflow.cc delete mode 100644 lib/asan/lit_tests/symbolize_callback.cc delete mode 100644 lib/asan/lit_tests/throw_call_test.cc delete mode 100644 lib/asan/lit_tests/throw_invoke_test.cc delete mode 100644 lib/asan/lit_tests/time_interceptor.cc delete mode 100644 lib/asan/lit_tests/unaligned_loads_and_stores.cc delete mode 100644 lib/asan/lit_tests/use-after-free-right.cc delete mode 100644 lib/asan/lit_tests/use-after-free.cc delete mode 100644 lib/asan/lit_tests/use-after-poison.cc delete mode 100644 lib/asan/lit_tests/use-after-scope-inlined.cc delete mode 100644 lib/asan/lit_tests/wait.cc create mode 100644 lib/asan/tests/asan_fake_stack_test.cc create mode 100644 lib/asan/tests/asan_interface_test.cc (limited to 'lib/asan') diff --git a/lib/asan/CMakeLists.txt b/lib/asan/CMakeLists.txt index a567a4d3e970..ad3f05488ebf 100644 --- a/lib/asan/CMakeLists.txt +++ b/lib/asan/CMakeLists.txt @@ -19,18 +19,19 @@ set(ASAN_SOURCES asan_stack.cc asan_stats.cc asan_thread.cc - asan_win.cc - ) - -set(ASAN_DYLIB_SOURCES - ${ASAN_SOURCES} - ) + asan_win.cc) include_directories(..) -set(ASAN_CFLAGS - ${SANITIZER_COMMON_CFLAGS} - -fno-rtti) +if (NOT MSVC) + set(ASAN_CFLAGS + ${SANITIZER_COMMON_CFLAGS} + -fno-rtti) +else() + set(ASAN_CFLAGS + ${SANITIZER_COMMON_CFLAGS} + /GR-) +endif() set(ASAN_COMMON_DEFINITIONS ASAN_HAS_EXCEPTIONS=1) @@ -40,6 +41,10 @@ if(ANDROID) ASAN_FLEXIBLE_MAPPING_AND_OFFSET=0 ASAN_NEEDS_SEGV=0 ASAN_LOW_MEMORY=1) +elseif(MSVC) + list(APPEND ASAN_COMMON_DEFINITIONS + ASAN_FLEXIBLE_MAPPING_AND_OFFSET=0 + ASAN_NEEDS_SEGV=0) else() list(APPEND ASAN_COMMON_DEFINITIONS ASAN_FLEXIBLE_MAPPING_AND_OFFSET=1 @@ -48,29 +53,55 @@ endif() # Architectures supported by ASan. filter_available_targets(ASAN_SUPPORTED_ARCH - x86_64 i386 powerpc64 powerpc) + x86_64 i386 powerpc64) +# Compile ASan sources into an object library. +if(APPLE) + foreach(os ${SANITIZER_COMMON_SUPPORTED_DARWIN_OS}) + add_compiler_rt_darwin_object_library(RTAsan ${os} + ARCH ${ASAN_SUPPORTED_ARCH} + SOURCES ${ASAN_SOURCES} + CFLAGS ${ASAN_CFLAGS} + DEFS ${ASAN_COMMON_DEFINITIONS}) + endforeach() +elseif(ANDROID) + add_library(RTAsan.arm.android OBJECT ${ASAN_SOURCES}) + set_target_compile_flags(RTAsan.arm.android ${ASAN_CFLAGS}) + set_property(TARGET RTAsan.arm.android APPEND PROPERTY + COMPILE_DEFINITIONS ${ASAN_COMMON_DEFINITIONS}) +else() + foreach(arch ${ASAN_SUPPORTED_ARCH}) + add_compiler_rt_object_library(RTAsan ${arch} + SOURCES ${ASAN_SOURCES} CFLAGS ${ASAN_CFLAGS} + DEFS ${ASAN_COMMON_DEFINITIONS}) + endforeach() +endif() + +# Build ASan runtimes shipped with Clang. set(ASAN_RUNTIME_LIBRARIES) if(APPLE) - # Build universal binary on APPLE. - add_compiler_rt_osx_dynamic_runtime(clang_rt.asan_osx_dynamic - ARCH ${ASAN_SUPPORTED_ARCH} - SOURCES ${ASAN_DYLIB_SOURCES} - $ - $ - CFLAGS ${ASAN_CFLAGS} - DEFS ${ASAN_COMMON_DEFINITIONS} + foreach (os ${SANITIZER_COMMON_SUPPORTED_DARWIN_OS}) # Dynamic lookup is needed because shadow scale and offset are # provided by the instrumented modules. - LINKFLAGS "-framework Foundation" - "-undefined dynamic_lookup") - list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan_osx_dynamic) + set(ASAN_RUNTIME_LDFLAGS + "-undefined dynamic_lookup") + add_compiler_rt_darwin_dynamic_runtime(clang_rt.asan_${os}_dynamic ${os} + ARCH ${ASAN_SUPPORTED_ARCH} + SOURCES $ + $ + $ + $ + CFLAGS ${ASAN_CFLAGS} + DEFS ${ASAN_COMMON_DEFINITIONS} + LINKFLAGS ${ASAN_RUNTIME_LDFLAGS}) + list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan_${os}_dynamic) + endforeach() + elseif(ANDROID) add_library(clang_rt.asan-arm-android SHARED - ${ASAN_SOURCES} + $ $ - $ - ) + $) set_target_compile_flags(clang_rt.asan-arm-android ${ASAN_CFLAGS}) set_property(TARGET clang_rt.asan-arm-android APPEND PROPERTY @@ -78,23 +109,44 @@ elseif(ANDROID) target_link_libraries(clang_rt.asan-arm-android dl) list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan-arm-android) else() - # Otherwise, build separate libraries for each target. + # Build separate libraries for each target. foreach(arch ${ASAN_SUPPORTED_ARCH}) + set(ASAN_RUNTIME_OBJECTS + $ + $ + $ + $) + if (NOT WIN32) + # We can't build Leak Sanitizer on Windows yet. + list(APPEND ASAN_RUNTIME_OBJECTS $) + endif() + add_compiler_rt_static_runtime(clang_rt.asan-${arch} ${arch} - SOURCES ${ASAN_SOURCES} - $ - $ - $ - $ + SOURCES ${ASAN_RUNTIME_OBJECTS} CFLAGS ${ASAN_CFLAGS} - DEFS ${ASAN_COMMON_DEFINITIONS} - SYMS asan.syms) + DEFS ${ASAN_COMMON_DEFINITIONS}) list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan-${arch}) + if (UNIX AND NOT ${arch} STREQUAL "i386") + add_sanitizer_rt_symbols(clang_rt.asan-${arch} asan.syms.extra) + list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan-${arch}-symbols) + endif() + + if (WIN32) + add_compiler_rt_static_runtime(clang_rt.asan_dll_thunk-${arch} ${arch} + SOURCES asan_dll_thunk.cc + CFLAGS ${ASAN_CFLAGS} -DASAN_DLL_THUNK + DEFS ${ASAN_COMMON_DEFINITIONS}) + list(APPEND ASAN_RUNTIME_LIBRARIES clang_rt.asan_dll_thunk-${arch}) + endif() endforeach() endif() add_compiler_rt_resource_file(asan_blacklist asan_blacklist.txt) +# All ASan runtime dependencies. +add_custom_target(asan_runtime_libraries + DEPENDS asan_blacklist ${ASAN_RUNTIME_LIBRARIES}) + if(LLVM_INCLUDE_TESTS) add_subdirectory(tests) endif() diff --git a/lib/asan/asan.syms b/lib/asan/asan.syms deleted file mode 100644 index fce367314093..000000000000 --- a/lib/asan/asan.syms +++ /dev/null @@ -1,5 +0,0 @@ -{ - __asan_*; - __sanitizer_syscall_pre_*; - __sanitizer_syscall_post_*; -}; diff --git a/lib/asan/asan.syms.extra b/lib/asan/asan.syms.extra new file mode 100644 index 000000000000..007aafe380a8 --- /dev/null +++ b/lib/asan/asan.syms.extra @@ -0,0 +1,3 @@ +__asan_* +__lsan_* +__ubsan_* diff --git a/lib/asan/asan_allocator.h b/lib/asan/asan_allocator.h index f817ce352ee2..c5fcbbb5d64b 100644 --- a/lib/asan/asan_allocator.h +++ b/lib/asan/asan_allocator.h @@ -35,10 +35,11 @@ void InitializeAllocator(); class AsanChunkView { public: explicit AsanChunkView(AsanChunk *chunk) : chunk_(chunk) {} - bool IsValid() { return chunk_ != 0; } - uptr Beg(); // first byte of user memory. - uptr End(); // last byte of user memory. - uptr UsedSize(); // size requested by the user. + bool IsValid(); // Checks if AsanChunkView points to a valid allocated + // or quarantined chunk. + uptr Beg(); // First byte of user memory. + uptr End(); // Last byte of user memory. + uptr UsedSize(); // Size requested by the user. uptr AllocTid(); uptr FreeTid(); void GetAllocStack(StackTrace *stack); @@ -114,7 +115,7 @@ void *asan_pvalloc(uptr size, StackTrace *stack); int asan_posix_memalign(void **memptr, uptr alignment, uptr size, StackTrace *stack); -uptr asan_malloc_usable_size(void *ptr, StackTrace *stack); +uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp); uptr asan_mz_size(const void *ptr); void asan_mz_force_lock(); diff --git a/lib/asan/asan_allocator2.cc b/lib/asan/asan_allocator2.cc index d74aa553a288..7a29975d711e 100644 --- a/lib/asan/asan_allocator2.cc +++ b/lib/asan/asan_allocator2.cc @@ -94,7 +94,7 @@ AllocatorCache *GetAllocatorCache(AsanThreadLocalMallocStorage *ms) { static Allocator allocator; static const uptr kMaxAllowedMallocSize = - FIRST_32_SECOND_64(3UL << 30, 8UL << 30); + FIRST_32_SECOND_64(3UL << 30, 64UL << 30); static const uptr kMaxThreadLocalQuarantine = FIRST_32_SECOND_64(1 << 18, 1 << 20); @@ -146,14 +146,15 @@ static uptr ComputeRZLog(uptr user_requested_size) { // ChunkBase consists of ChunkHeader and other bytes that overlap with user // memory. -// If a memory chunk is allocated by memalign and we had to increase the -// allocation size to achieve the proper alignment, then we store this magic +// If the left redzone is greater than the ChunkHeader size we store a magic // value in the first uptr word of the memory block and store the address of // ChunkBase in the next uptr. -// M B ? ? ? L L L L L L H H U U U U U U -// M -- magic value kMemalignMagic +// M B L L L L L L L L L H H U U U U U U +// | ^ +// ---------------------| +// M -- magic value kAllocBegMagic // B -- address of ChunkHeader pointing to the first 'H' -static const uptr kMemalignMagic = 0xCC6E96B9; +static const uptr kAllocBegMagic = 0xCC6E96B9; struct ChunkHeader { // 1-st 8 bytes. @@ -185,14 +186,19 @@ COMPILER_CHECK(kChunkHeader2Size <= 16); struct AsanChunk: ChunkBase { uptr Beg() { return reinterpret_cast(this) + kChunkHeaderSize; } - uptr UsedSize() { + uptr UsedSize(bool locked_version = false) { if (user_requested_size != SizeClassMap::kMaxSize) return user_requested_size; - return *reinterpret_cast(allocator.GetMetaData(AllocBeg())); - } - void *AllocBeg() { - if (from_memalign) + return *reinterpret_cast( + allocator.GetMetaData(AllocBeg(locked_version))); + } + void *AllocBeg(bool locked_version = false) { + if (from_memalign) { + if (locked_version) + return allocator.GetBlockBeginFastLocked( + reinterpret_cast(this)); return allocator.GetBlockBegin(reinterpret_cast(this)); + } return reinterpret_cast(Beg() - RZLog2Size(rz_log)); } // If we don't use stack depot, we store the alloc/free stack traces @@ -212,11 +218,14 @@ struct AsanChunk: ChunkBase { uptr available = RoundUpTo(user_requested_size, SHADOW_GRANULARITY); return (available - kChunkHeader2Size) / sizeof(u32); } - bool AddrIsInside(uptr addr) { - return (addr >= Beg()) && (addr < Beg() + UsedSize()); + bool AddrIsInside(uptr addr, bool locked_version = false) { + return (addr >= Beg()) && (addr < Beg() + UsedSize(locked_version)); } }; +bool AsanChunkView::IsValid() { + return chunk_ != 0 && chunk_->chunk_state != CHUNK_AVAILABLE; +} uptr AsanChunkView::Beg() { return chunk_->Beg(); } uptr AsanChunkView::End() { return Beg() + UsedSize(); } uptr AsanChunkView::UsedSize() { return chunk_->UsedSize(); } @@ -227,25 +236,16 @@ static void GetStackTraceFromId(u32 id, StackTrace *stack) { CHECK(id); uptr size = 0; const uptr *trace = StackDepotGet(id, &size); - CHECK_LT(size, kStackTraceMax); - internal_memcpy(stack->trace, trace, sizeof(uptr) * size); - stack->size = size; + CHECK(trace); + stack->CopyFrom(trace, size); } void AsanChunkView::GetAllocStack(StackTrace *stack) { - if (flags()->use_stack_depot) - GetStackTraceFromId(chunk_->alloc_context_id, stack); - else - StackTrace::UncompressStack(stack, chunk_->AllocStackBeg(), - chunk_->AllocStackSize()); + GetStackTraceFromId(chunk_->alloc_context_id, stack); } void AsanChunkView::GetFreeStack(StackTrace *stack) { - if (flags()->use_stack_depot) - GetStackTraceFromId(chunk_->free_context_id, stack); - else - StackTrace::UncompressStack(stack, chunk_->FreeStackBeg(), - chunk_->FreeStackSize()); + GetStackTraceFromId(chunk_->free_context_id, stack); } struct QuarantineCallback; @@ -276,10 +276,13 @@ struct QuarantineCallback { RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY), kAsanHeapLeftRedzoneMagic); void *p = reinterpret_cast(m->AllocBeg()); - if (m->from_memalign) { - uptr *memalign_magic = reinterpret_cast(p); - CHECK_EQ(memalign_magic[0], kMemalignMagic); - CHECK_EQ(memalign_magic[1], reinterpret_cast(m)); + if (p != m) { + uptr *alloc_magic = reinterpret_cast(p); + CHECK_EQ(alloc_magic[0], kAllocBegMagic); + // Clear the magic value, as allocator internals may overwrite the + // contents of deallocated chunk, confusing GetAsanChunk lookup. + alloc_magic[0] = 0; + CHECK_EQ(alloc_magic[1], reinterpret_cast(m)); } // Statistics. @@ -341,7 +344,7 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack, if (size > kMaxAllowedMallocSize || needed_size > kMaxAllowedMallocSize) { Report("WARNING: AddressSanitizer failed to allocate %p bytes\n", (void*)size); - return 0; + return AllocatorReturnNull(); } AsanThread *t = GetCurrentThread(); @@ -355,8 +358,6 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack, allocated = allocator.Allocate(cache, needed_size, 8, false); } uptr alloc_beg = reinterpret_cast(allocated); - // Clear the first allocated word (an old kMemalignMagic may still be there). - reinterpret_cast(alloc_beg)[0] = 0; uptr alloc_end = alloc_beg + needed_size; uptr beg_plus_redzone = alloc_beg + rz_size; uptr user_beg = beg_plus_redzone; @@ -373,11 +374,10 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack, CHECK_EQ(alloc_tid, m->alloc_tid); // Does alloc_tid fit into the bitfield? m->free_tid = kInvalidTid; m->from_memalign = user_beg != beg_plus_redzone; - if (m->from_memalign) { - CHECK_LE(beg_plus_redzone + 2 * sizeof(uptr), user_beg); - uptr *memalign_magic = reinterpret_cast(alloc_beg); - memalign_magic[0] = kMemalignMagic; - memalign_magic[1] = chunk_beg; + if (alloc_beg != chunk_beg) { + CHECK_LE(alloc_beg+ 2 * sizeof(uptr), chunk_beg); + reinterpret_cast(alloc_beg)[0] = kAllocBegMagic; + reinterpret_cast(alloc_beg)[1] = chunk_beg; } if (using_primary_allocator) { CHECK(size); @@ -391,12 +391,7 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack, meta[1] = chunk_beg; } - if (fl.use_stack_depot) { - m->alloc_context_id = StackDepotPut(stack->trace, stack->size); - } else { - m->alloc_context_id = 0; - StackTrace::CompressStack(stack, m->AllocStackBeg(), m->AllocStackSize()); - } + m->alloc_context_id = StackDepotPut(stack->trace, stack->size); uptr size_rounded_down_to_granularity = RoundDownTo(size, SHADOW_GRANULARITY); // Unpoison the bulk of the memory region. @@ -405,7 +400,7 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack, // Deal with the end of the region if size is not aligned to granularity. if (size != size_rounded_down_to_granularity && fl.poison_heap) { u8 *shadow = (u8*)MemToShadow(user_beg + size_rounded_down_to_granularity); - *shadow = size & (SHADOW_GRANULARITY - 1); + *shadow = fl.poison_partial ? (size & (SHADOW_GRANULARITY - 1)) : 0; } AsanStats &thread_stats = GetCurrentThreadStats(); @@ -422,23 +417,30 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack, uptr fill_size = Min(size, (uptr)fl.max_malloc_fill_size); REAL(memset)(res, fl.malloc_fill_byte, fill_size); } +#if CAN_SANITIZE_LEAKS + m->lsan_tag = __lsan::DisabledInThisThread() ? __lsan::kIgnored + : __lsan::kDirectlyLeaked; +#endif // Must be the last mutation of metadata in this function. atomic_store((atomic_uint8_t *)m, CHUNK_ALLOCATED, memory_order_release); ASAN_MALLOC_HOOK(res, size); return res; } +static void ReportInvalidFree(void *ptr, u8 chunk_state, StackTrace *stack) { + if (chunk_state == CHUNK_QUARANTINE) + ReportDoubleFree((uptr)ptr, stack); + else + ReportFreeNotMalloced((uptr)ptr, stack); +} + static void AtomicallySetQuarantineFlag(AsanChunk *m, void *ptr, StackTrace *stack) { u8 old_chunk_state = CHUNK_ALLOCATED; // Flip the chunk_state atomically to avoid race on double-free. if (!atomic_compare_exchange_strong((atomic_uint8_t*)m, &old_chunk_state, - CHUNK_QUARANTINE, memory_order_acquire)) { - if (old_chunk_state == CHUNK_QUARANTINE) - ReportDoubleFree((uptr)ptr, stack); - else - ReportFreeNotMalloced((uptr)ptr, stack); - } + CHUNK_QUARANTINE, memory_order_acquire)) + ReportInvalidFree(ptr, old_chunk_state, stack); CHECK_EQ(CHUNK_ALLOCATED, old_chunk_state); } @@ -448,12 +450,6 @@ static void QuarantineChunk(AsanChunk *m, void *ptr, StackTrace *stack, AllocType alloc_type) { CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE); - // FIXME: if the free hook produces an ASan report (e.g. due to a bug), - // printing the report may crash as the AsanChunk free-related fields have not - // been updated yet. We might need to introduce yet another chunk state to - // handle this correctly, but don't want to yet. - ASAN_FREE_HOOK(ptr); - if (m->alloc_type != alloc_type && flags()->alloc_dealloc_mismatch) ReportAllocTypeMismatch((uptr)ptr, stack, (AllocType)m->alloc_type, (AllocType)alloc_type); @@ -463,12 +459,7 @@ static void QuarantineChunk(AsanChunk *m, void *ptr, CHECK_EQ(m->free_tid, kInvalidTid); AsanThread *t = GetCurrentThread(); m->free_tid = t ? t->tid() : 0; - if (flags()->use_stack_depot) { - m->free_context_id = StackDepotPut(stack->trace, stack->size); - } else { - m->free_context_id = 0; - StackTrace::CompressStack(stack, m->FreeStackBeg(), m->FreeStackSize()); - } + m->free_context_id = StackDepotPut(stack->trace, stack->size); // Poison the region. PoisonShadow(m->Beg(), RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY), @@ -498,6 +489,7 @@ static void Deallocate(void *ptr, StackTrace *stack, AllocType alloc_type) { uptr chunk_beg = p - kChunkHeaderSize; AsanChunk *m = reinterpret_cast(chunk_beg); + ASAN_FREE_HOOK(ptr); // Must mark the chunk as quarantined before any changes to its metadata. AtomicallySetQuarantineFlag(m, ptr, stack); QuarantineChunk(m, ptr, stack, alloc_type); @@ -513,50 +505,45 @@ static void *Reallocate(void *old_ptr, uptr new_size, StackTrace *stack) { thread_stats.reallocs++; thread_stats.realloced += new_size; - // Must mark the chunk as quarantined before any changes to its metadata. - // This also ensures that other threads can't deallocate it in the meantime. - AtomicallySetQuarantineFlag(m, old_ptr, stack); - - uptr old_size = m->UsedSize(); - uptr memcpy_size = Min(new_size, old_size); void *new_ptr = Allocate(new_size, 8, stack, FROM_MALLOC, true); if (new_ptr) { + u8 chunk_state = m->chunk_state; + if (chunk_state != CHUNK_ALLOCATED) + ReportInvalidFree(old_ptr, chunk_state, stack); CHECK_NE(REAL(memcpy), (void*)0); + uptr memcpy_size = Min(new_size, m->UsedSize()); + // If realloc() races with free(), we may start copying freed memory. + // However, we will report racy double-free later anyway. REAL(memcpy)(new_ptr, old_ptr, memcpy_size); - QuarantineChunk(m, old_ptr, stack, FROM_MALLOC); + Deallocate(old_ptr, stack, FROM_MALLOC); } return new_ptr; } -static AsanChunk *GetAsanChunkByAddr(uptr p) { - void *ptr = reinterpret_cast(p); - uptr alloc_beg = reinterpret_cast(allocator.GetBlockBegin(ptr)); +// Assumes alloc_beg == allocator.GetBlockBegin(alloc_beg). +static AsanChunk *GetAsanChunk(void *alloc_beg) { if (!alloc_beg) return 0; - uptr *memalign_magic = reinterpret_cast(alloc_beg); - if (memalign_magic[0] == kMemalignMagic) { - AsanChunk *m = reinterpret_cast(memalign_magic[1]); - CHECK(m->from_memalign); - return m; - } - if (!allocator.FromPrimary(ptr)) { - uptr *meta = reinterpret_cast( - allocator.GetMetaData(reinterpret_cast(alloc_beg))); + if (!allocator.FromPrimary(alloc_beg)) { + uptr *meta = reinterpret_cast(allocator.GetMetaData(alloc_beg)); AsanChunk *m = reinterpret_cast(meta[1]); return m; } - uptr actual_size = allocator.GetActuallyAllocatedSize(ptr); - CHECK_LE(actual_size, SizeClassMap::kMaxSize); - // We know the actually allocted size, but we don't know the redzone size. - // Just try all possible redzone sizes. - for (u32 rz_log = 0; rz_log < 8; rz_log++) { - u32 rz_size = RZLog2Size(rz_log); - uptr max_possible_size = actual_size - rz_size; - if (ComputeRZLog(max_possible_size) != rz_log) - continue; - return reinterpret_cast( - alloc_beg + rz_size - kChunkHeaderSize); - } - return 0; + uptr *alloc_magic = reinterpret_cast(alloc_beg); + if (alloc_magic[0] == kAllocBegMagic) + return reinterpret_cast(alloc_magic[1]); + return reinterpret_cast(alloc_beg); +} + +static AsanChunk *GetAsanChunkByAddr(uptr p) { + void *alloc_beg = allocator.GetBlockBegin(reinterpret_cast(p)); + return GetAsanChunk(alloc_beg); +} + +// Allocator must be locked when this function is called. +static AsanChunk *GetAsanChunkByAddrFastLocked(uptr p) { + void *alloc_beg = + allocator.GetBlockBeginFastLocked(reinterpret_cast(p)); + return GetAsanChunk(alloc_beg); } static uptr AllocationSize(uptr p) { @@ -621,24 +608,22 @@ void PrintInternalAllocatorStats() { allocator.PrintStats(); } -SANITIZER_INTERFACE_ATTRIBUTE void *asan_memalign(uptr alignment, uptr size, StackTrace *stack, AllocType alloc_type) { return Allocate(size, alignment, stack, alloc_type, true); } -SANITIZER_INTERFACE_ATTRIBUTE void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type) { Deallocate(ptr, stack, alloc_type); } -SANITIZER_INTERFACE_ATTRIBUTE void *asan_malloc(uptr size, StackTrace *stack) { return Allocate(size, 8, stack, FROM_MALLOC, true); } void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack) { - if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0; + if (CallocShouldReturnNullDueToOverflow(size, nmemb)) + return AllocatorReturnNull(); void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC, false); // If the memory comes from the secondary allocator no need to clear it // as it comes directly from mmap. @@ -679,12 +664,13 @@ int asan_posix_memalign(void **memptr, uptr alignment, uptr size, return 0; } -uptr asan_malloc_usable_size(void *ptr, StackTrace *stack) { - CHECK(stack); +uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp) { if (ptr == 0) return 0; uptr usable_size = AllocationSize(reinterpret_cast(ptr)); - if (flags()->check_malloc_usable_size && (usable_size == 0)) - ReportMallocUsableSizeNotOwned((uptr)ptr, stack); + if (flags()->check_malloc_usable_size && (usable_size == 0)) { + GET_STACK_TRACE_FATAL(pc, bp); + ReportMallocUsableSizeNotOwned((uptr)ptr, &stack); + } return usable_size; } @@ -719,25 +705,26 @@ void GetAllocatorGlobalRange(uptr *begin, uptr *end) { *end = *begin + sizeof(__asan::allocator); } -void *PointsIntoChunk(void* p) { +uptr PointsIntoChunk(void* p) { uptr addr = reinterpret_cast(p); - __asan::AsanChunk *m = __asan::GetAsanChunkByAddr(addr); + __asan::AsanChunk *m = __asan::GetAsanChunkByAddrFastLocked(addr); if (!m) return 0; uptr chunk = m->Beg(); - if ((m->chunk_state == __asan::CHUNK_ALLOCATED) && m->AddrIsInside(addr)) - return reinterpret_cast(chunk); + if ((m->chunk_state == __asan::CHUNK_ALLOCATED) && + m->AddrIsInside(addr, /*locked_version=*/true)) + return chunk; return 0; } -void *GetUserBegin(void *p) { - __asan::AsanChunk *m = __asan::GetAsanChunkByAddr(reinterpret_cast(p)); +uptr GetUserBegin(uptr chunk) { + __asan::AsanChunk *m = + __asan::GetAsanChunkByAddrFastLocked(chunk); CHECK(m); - return reinterpret_cast(m->Beg()); + return m->Beg(); } -LsanMetadata::LsanMetadata(void *chunk) { - uptr addr = reinterpret_cast(chunk); - metadata_ = reinterpret_cast(addr - __asan::kChunkHeaderSize); +LsanMetadata::LsanMetadata(uptr chunk) { + metadata_ = reinterpret_cast(chunk - __asan::kChunkHeaderSize); } bool LsanMetadata::allocated() const { @@ -757,7 +744,7 @@ void LsanMetadata::set_tag(ChunkTag value) { uptr LsanMetadata::requested_size() const { __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_); - return m->UsedSize(); + return m->UsedSize(/*locked_version=*/true); } u32 LsanMetadata::stack_trace_id() const { @@ -765,18 +752,23 @@ u32 LsanMetadata::stack_trace_id() const { return m->alloc_context_id; } -template void ForEachChunk(Callable const &callback) { - __asan::allocator.ForEachChunk(callback); +void ForEachChunk(ForEachChunkCallback callback, void *arg) { + __asan::allocator.ForEachChunk(callback, arg); +} + +IgnoreObjectResult IgnoreObjectLocked(const void *p) { + uptr addr = reinterpret_cast(p); + __asan::AsanChunk *m = __asan::GetAsanChunkByAddr(addr); + if (!m) return kIgnoreObjectInvalid; + if ((m->chunk_state == __asan::CHUNK_ALLOCATED) && m->AddrIsInside(addr)) { + if (m->lsan_tag == kIgnored) + return kIgnoreObjectAlreadyIgnored; + m->lsan_tag = __lsan::kIgnored; + return kIgnoreObjectSuccess; + } else { + return kIgnoreObjectInvalid; + } } -#if CAN_SANITIZE_LEAKS -template void ForEachChunk( - ProcessPlatformSpecificAllocationsCb const &callback); -template void ForEachChunk(PrintLeakedCb const &callback); -template void ForEachChunk(CollectLeaksCb const &callback); -template void ForEachChunk( - MarkIndirectlyLeakedCb const &callback); -template void ForEachChunk(ClearTagCb const &callback); -#endif // CAN_SANITIZE_LEAKS } // namespace __lsan // ---------------------- Interface ---------------- {{{1 @@ -808,12 +800,12 @@ uptr __asan_get_allocated_size(const void *p) { #if !SANITIZER_SUPPORTS_WEAK_HOOKS // Provide default (no-op) implementation of malloc hooks. extern "C" { -SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void __asan_malloc_hook(void *ptr, uptr size) { (void)ptr; (void)size; } -SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void __asan_free_hook(void *ptr) { (void)ptr; } diff --git a/lib/asan/asan_blacklist.txt b/lib/asan/asan_blacklist.txt index 03da08598d23..63b3c315b26b 100644 --- a/lib/asan/asan_blacklist.txt +++ b/lib/asan/asan_blacklist.txt @@ -6,5 +6,5 @@ # fun:*bad_function_name* # src:file_with_tricky_code.cc # global:*global_with_bad_access_or_initialization* -# global-init:*global_with_initialization_issues* -# global-init-type:*Namespace::ClassName* +# global:*global_with_initialization_issues*=init +# type:*Namespace::ClassName*=init diff --git a/lib/asan/asan_dll_thunk.cc b/lib/asan/asan_dll_thunk.cc new file mode 100644 index 000000000000..cedd60d342f6 --- /dev/null +++ b/lib/asan/asan_dll_thunk.cc @@ -0,0 +1,196 @@ +//===-- asan_dll_thunk.cc -------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// This file defines a family of thunks that should be statically linked into +// the DLLs that have ASan instrumentation in order to delegate the calls to the +// shared runtime that lives in the main binary. +// See https://code.google.com/p/address-sanitizer/issues/detail?id=209 for the +// details. +//===----------------------------------------------------------------------===// + +// Only compile this code when buidling asan_dll_thunk.lib +// Using #ifdef rather than relying on Makefiles etc. +// simplifies the build procedure. +#ifdef ASAN_DLL_THUNK + +// ----------------- Helper functions and macros --------------------- {{{1 +extern "C" { +void *__stdcall GetModuleHandleA(const char *module_name); +void *__stdcall GetProcAddress(void *module, const char *proc_name); +void abort(); +} + +static void *getRealProcAddressOrDie(const char *name) { + void *ret = GetProcAddress(GetModuleHandleA(0), name); + if (!ret) + abort(); + return ret; +} + +#define WRAP_V_V(name) \ + extern "C" void name() { \ + typedef void (*fntype)(); \ + static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ + fn(); \ + } + +#define WRAP_V_W(name) \ + extern "C" void name(void *arg) { \ + typedef void (*fntype)(void *arg); \ + static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ + fn(arg); \ + } + +#define WRAP_V_WW(name) \ + extern "C" void name(void *arg1, void *arg2) { \ + typedef void (*fntype)(void *, void *); \ + static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ + fn(arg1, arg2); \ + } + +#define WRAP_V_WWW(name) \ + extern "C" void name(void *arg1, void *arg2, void *arg3) { \ + typedef void *(*fntype)(void *, void *, void *); \ + static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ + fn(arg1, arg2, arg3); \ + } + +#define WRAP_W_V(name) \ + extern "C" void *name() { \ + typedef void *(*fntype)(); \ + static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ + return fn(); \ + } + +#define WRAP_W_W(name) \ + extern "C" void *name(void *arg) { \ + typedef void *(*fntype)(void *arg); \ + static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ + return fn(arg); \ + } + +#define WRAP_W_WW(name) \ + extern "C" void *name(void *arg1, void *arg2) { \ + typedef void *(*fntype)(void *, void *); \ + static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ + return fn(arg1, arg2); \ + } + +#define WRAP_W_WWW(name) \ + extern "C" void *name(void *arg1, void *arg2, void *arg3) { \ + typedef void *(*fntype)(void *, void *, void *); \ + static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ + return fn(arg1, arg2, arg3); \ + } + +#define WRAP_W_WWWW(name) \ + extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) { \ + typedef void *(*fntype)(void *, void *, void *, void *); \ + static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ + return fn(arg1, arg2, arg3, arg4); \ + } + +#define WRAP_W_WWWWW(name) \ + extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \ + void *arg5) { \ + typedef void *(*fntype)(void *, void *, void *, void *, void *); \ + static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ + return fn(arg1, arg2, arg3, arg4, arg5); \ + } + +#define WRAP_W_WWWWWW(name) \ + extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \ + void *arg5, void *arg6) { \ + typedef void *(*fntype)(void *, void *, void *, void *, void *, void *); \ + static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ + return fn(arg1, arg2, arg3, arg4, arg5, arg6); \ + } +// }}} + +// ----------------- ASan own interface functions -------------------- +WRAP_W_V(__asan_should_detect_stack_use_after_return) + +extern "C" { + int __asan_option_detect_stack_use_after_return; + + // Manually wrap __asan_init as we need to initialize + // __asan_option_detect_stack_use_after_return afterwards. + void __asan_init_v3() { + typedef void (*fntype)(); + static fntype fn = (fntype)getRealProcAddressOrDie("__asan_init_v3"); + fn(); + __asan_option_detect_stack_use_after_return = + (__asan_should_detect_stack_use_after_return() != 0); + } +} + +WRAP_V_W(__asan_report_store1) +WRAP_V_W(__asan_report_store2) +WRAP_V_W(__asan_report_store4) +WRAP_V_W(__asan_report_store8) +WRAP_V_W(__asan_report_store16) +WRAP_V_WW(__asan_report_store_n) + +WRAP_V_W(__asan_report_load1) +WRAP_V_W(__asan_report_load2) +WRAP_V_W(__asan_report_load4) +WRAP_V_W(__asan_report_load8) +WRAP_V_W(__asan_report_load16) +WRAP_V_WW(__asan_report_load_n) + +WRAP_V_WW(__asan_register_globals) +WRAP_V_WW(__asan_unregister_globals) + +WRAP_W_WW(__asan_stack_malloc_0) +WRAP_W_WW(__asan_stack_malloc_1) +WRAP_W_WW(__asan_stack_malloc_2) +WRAP_W_WW(__asan_stack_malloc_3) +WRAP_W_WW(__asan_stack_malloc_4) +WRAP_W_WW(__asan_stack_malloc_5) +WRAP_W_WW(__asan_stack_malloc_6) +WRAP_W_WW(__asan_stack_malloc_7) +WRAP_W_WW(__asan_stack_malloc_8) +WRAP_W_WW(__asan_stack_malloc_9) +WRAP_W_WW(__asan_stack_malloc_10) + +WRAP_V_WWW(__asan_stack_free_0) +WRAP_V_WWW(__asan_stack_free_1) +WRAP_V_WWW(__asan_stack_free_2) +WRAP_V_WWW(__asan_stack_free_4) +WRAP_V_WWW(__asan_stack_free_5) +WRAP_V_WWW(__asan_stack_free_6) +WRAP_V_WWW(__asan_stack_free_7) +WRAP_V_WWW(__asan_stack_free_8) +WRAP_V_WWW(__asan_stack_free_9) +WRAP_V_WWW(__asan_stack_free_10) + +// TODO(timurrrr): Add more interface functions on the as-needed basis. + +// ----------------- Memory allocation functions --------------------- +WRAP_V_W(free) +WRAP_V_WW(_free_dbg) + +WRAP_W_W(malloc) +WRAP_W_WWWW(_malloc_dbg) + +WRAP_W_WW(calloc) +WRAP_W_WWWWW(_calloc_dbg) +WRAP_W_WWW(_calloc_impl) + +WRAP_W_WW(realloc) +WRAP_W_WWW(_realloc_dbg) +WRAP_W_WWW(_recalloc) + +WRAP_W_W(_msize) + +// TODO(timurrrr): Do we need to add _Crt* stuff here? (see asan_malloc_win.cc). + +#endif // ASAN_DLL_THUNK diff --git a/lib/asan/asan_fake_stack.cc b/lib/asan/asan_fake_stack.cc index 23eebe64e612..d3e55bff1e6e 100644 --- a/lib/asan/asan_fake_stack.cc +++ b/lib/asan/asan_fake_stack.cc @@ -17,167 +17,204 @@ namespace __asan { -FakeStack::FakeStack() { - CHECK(REAL(memset)); - REAL(memset)(this, 0, sizeof(*this)); +static const u64 kMagic1 = kAsanStackAfterReturnMagic; +static const u64 kMagic2 = (kMagic1 << 8) | kMagic1; +static const u64 kMagic4 = (kMagic2 << 16) | kMagic2; +static const u64 kMagic8 = (kMagic4 << 32) | kMagic4; + +// For small size classes inline PoisonShadow for better performance. +ALWAYS_INLINE void SetShadow(uptr ptr, uptr size, uptr class_id, u64 magic) { + CHECK_EQ(SHADOW_SCALE, 3); // This code expects SHADOW_SCALE=3. + u64 *shadow = reinterpret_cast(MemToShadow(ptr)); + if (class_id <= 6) { + for (uptr i = 0; i < (1U << class_id); i++) + shadow[i] = magic; + } else { + // The size class is too big, it's cheaper to poison only size bytes. + PoisonShadow(ptr, size, static_cast(magic)); + } } -bool FakeStack::AddrIsInSizeClass(uptr addr, uptr size_class) { - uptr mem = allocated_size_classes_[size_class]; - uptr size = ClassMmapSize(size_class); - bool res = mem && addr >= mem && addr < mem + size; +FakeStack *FakeStack::Create(uptr stack_size_log) { + static uptr kMinStackSizeLog = 16; + static uptr kMaxStackSizeLog = FIRST_32_SECOND_64(24, 28); + if (stack_size_log < kMinStackSizeLog) + stack_size_log = kMinStackSizeLog; + if (stack_size_log > kMaxStackSizeLog) + stack_size_log = kMaxStackSizeLog; + FakeStack *res = reinterpret_cast( + MmapOrDie(RequiredSize(stack_size_log), "FakeStack")); + res->stack_size_log_ = stack_size_log; + if (common_flags()->verbosity) { + u8 *p = reinterpret_cast(res); + Report("T%d: FakeStack created: %p -- %p stack_size_log: %zd \n", + GetCurrentTidOrInvalid(), p, + p + FakeStack::RequiredSize(stack_size_log), stack_size_log); + } return res; } -uptr FakeStack::AddrIsInFakeStack(uptr addr) { - for (uptr size_class = 0; size_class < kNumberOfSizeClasses; size_class++) { - if (!AddrIsInSizeClass(addr, size_class)) continue; - uptr size_class_first_ptr = allocated_size_classes_[size_class]; - uptr size = ClassSize(size_class); - CHECK_LE(size_class_first_ptr, addr); - CHECK_GT(size_class_first_ptr + ClassMmapSize(size_class), addr); - return size_class_first_ptr + ((addr - size_class_first_ptr) / size) * size; - } - return 0; +void FakeStack::Destroy() { + PoisonAll(0); + UnmapOrDie(this, RequiredSize(stack_size_log_)); } -// We may want to compute this during compilation. -ALWAYS_INLINE uptr FakeStack::ComputeSizeClass(uptr alloc_size) { - uptr rounded_size = RoundUpToPowerOfTwo(alloc_size); - uptr log = Log2(rounded_size); - CHECK_LE(alloc_size, (1UL << log)); - CHECK_GT(alloc_size, (1UL << (log-1))); - uptr res = log < kMinStackFrameSizeLog ? 0 : log - kMinStackFrameSizeLog; - CHECK_LT(res, kNumberOfSizeClasses); - CHECK_GE(ClassSize(res), rounded_size); - return res; +void FakeStack::PoisonAll(u8 magic) { + PoisonShadow(reinterpret_cast(this), RequiredSize(stack_size_log()), + magic); } -void FakeFrameFifo::FifoPush(FakeFrame *node) { - CHECK(node); - node->next = 0; - if (first_ == 0 && last_ == 0) { - first_ = last_ = node; - } else { - CHECK(first_); - CHECK(last_); - last_->next = node; - last_ = node; +ALWAYS_INLINE USED +FakeFrame *FakeStack::Allocate(uptr stack_size_log, uptr class_id, + uptr real_stack) { + CHECK_LT(class_id, kNumberOfSizeClasses); + if (needs_gc_) + GC(real_stack); + uptr &hint_position = hint_position_[class_id]; + const int num_iter = NumberOfFrames(stack_size_log, class_id); + u8 *flags = GetFlags(stack_size_log, class_id); + for (int i = 0; i < num_iter; i++) { + uptr pos = ModuloNumberOfFrames(stack_size_log, class_id, hint_position++); + // This part is tricky. On one hand, checking and setting flags[pos] + // should be atomic to ensure async-signal safety. But on the other hand, + // if the signal arrives between checking and setting flags[pos], the + // signal handler's fake stack will start from a different hint_position + // and so will not touch this particular byte. So, it is safe to do this + // with regular non-atimic load and store (at least I was not able to make + // this code crash). + if (flags[pos]) continue; + flags[pos] = 1; + FakeFrame *res = reinterpret_cast( + GetFrame(stack_size_log, class_id, pos)); + res->real_stack = real_stack; + *SavedFlagPtr(reinterpret_cast(res), class_id) = &flags[pos]; + return res; } + return 0; // We are out of fake stack. } -FakeFrame *FakeFrameFifo::FifoPop() { - CHECK(first_ && last_ && "Exhausted fake stack"); - FakeFrame *res = 0; - if (first_ == last_) { - res = first_; - first_ = last_ = 0; - } else { - res = first_; - first_ = first_->next; - } - return res; +uptr FakeStack::AddrIsInFakeStack(uptr ptr) { + uptr stack_size_log = this->stack_size_log(); + uptr beg = reinterpret_cast(GetFrame(stack_size_log, 0, 0)); + uptr end = reinterpret_cast(this) + RequiredSize(stack_size_log); + if (ptr < beg || ptr >= end) return 0; + uptr class_id = (ptr - beg) >> stack_size_log; + uptr base = beg + (class_id << stack_size_log); + CHECK_LE(base, ptr); + CHECK_LT(ptr, base + (1UL << stack_size_log)); + uptr pos = (ptr - base) >> (kMinStackFrameSizeLog + class_id); + return base + pos * BytesInSizeClass(class_id); } -void FakeStack::Init(uptr stack_size) { - stack_size_ = stack_size; - alive_ = true; +void FakeStack::HandleNoReturn() { + needs_gc_ = true; } -void FakeStack::Cleanup() { - alive_ = false; - for (uptr i = 0; i < kNumberOfSizeClasses; i++) { - uptr mem = allocated_size_classes_[i]; - if (mem) { - PoisonShadow(mem, ClassMmapSize(i), 0); - allocated_size_classes_[i] = 0; - UnmapOrDie((void*)mem, ClassMmapSize(i)); +// When throw, longjmp or some such happens we don't call OnFree() and +// as the result may leak one or more fake frames, but the good news is that +// we are notified about all such events by HandleNoReturn(). +// If we recently had such no-return event we need to collect garbage frames. +// We do it based on their 'real_stack' values -- everything that is lower +// than the current real_stack is garbage. +NOINLINE void FakeStack::GC(uptr real_stack) { + uptr collected = 0; + for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++) { + u8 *flags = GetFlags(stack_size_log(), class_id); + for (uptr i = 0, n = NumberOfFrames(stack_size_log(), class_id); i < n; + i++) { + if (flags[i] == 0) continue; // not allocated. + FakeFrame *ff = reinterpret_cast( + GetFrame(stack_size_log(), class_id, i)); + if (ff->real_stack < real_stack) { + flags[i] = 0; + collected++; + } } } + needs_gc_ = false; } -uptr FakeStack::ClassMmapSize(uptr size_class) { - return RoundUpToPowerOfTwo(stack_size_); +void FakeStack::ForEachFakeFrame(RangeIteratorCallback callback, void *arg) { + for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++) { + u8 *flags = GetFlags(stack_size_log(), class_id); + for (uptr i = 0, n = NumberOfFrames(stack_size_log(), class_id); i < n; + i++) { + if (flags[i] == 0) continue; // not allocated. + FakeFrame *ff = reinterpret_cast( + GetFrame(stack_size_log(), class_id, i)); + uptr begin = reinterpret_cast(ff); + callback(begin, begin + FakeStack::BytesInSizeClass(class_id), arg); + } + } } -void FakeStack::AllocateOneSizeClass(uptr size_class) { - CHECK(ClassMmapSize(size_class) >= GetPageSizeCached()); - uptr new_mem = (uptr)MmapOrDie( - ClassMmapSize(size_class), __FUNCTION__); - // Printf("T%d new_mem[%zu]: %p-%p mmap %zu\n", - // GetCurrentThread()->tid(), - // size_class, new_mem, new_mem + ClassMmapSize(size_class), - // ClassMmapSize(size_class)); - uptr i; - for (i = 0; i < ClassMmapSize(size_class); - i += ClassSize(size_class)) { - size_classes_[size_class].FifoPush((FakeFrame*)(new_mem + i)); - } - CHECK(i == ClassMmapSize(size_class)); - allocated_size_classes_[size_class] = new_mem; +#if SANITIZER_LINUX && !SANITIZER_ANDROID +static THREADLOCAL FakeStack *fake_stack_tls; + +FakeStack *GetTLSFakeStack() { + return fake_stack_tls; +} +void SetTLSFakeStack(FakeStack *fs) { + fake_stack_tls = fs; } +#else +FakeStack *GetTLSFakeStack() { return 0; } +void SetTLSFakeStack(FakeStack *fs) { } +#endif // SANITIZER_LINUX && !SANITIZER_ANDROID -ALWAYS_INLINE uptr FakeStack::AllocateStack(uptr size, uptr real_stack) { - if (!alive_) return real_stack; - CHECK(size <= kMaxStackMallocSize && size > 1); - uptr size_class = ComputeSizeClass(size); - if (!allocated_size_classes_[size_class]) { - AllocateOneSizeClass(size_class); - } - FakeFrame *fake_frame = size_classes_[size_class].FifoPop(); - CHECK(fake_frame); - fake_frame->size_minus_one = size - 1; - fake_frame->real_stack = real_stack; - while (FakeFrame *top = call_stack_.top()) { - if (top->real_stack > real_stack) break; - call_stack_.LifoPop(); - DeallocateFrame(top); - } - call_stack_.LifoPush(fake_frame); - uptr ptr = (uptr)fake_frame; - PoisonShadow(ptr, size, 0); - return ptr; +static FakeStack *GetFakeStack() { + AsanThread *t = GetCurrentThread(); + if (!t) return 0; + return t->fake_stack(); } -ALWAYS_INLINE void FakeStack::DeallocateFrame(FakeFrame *fake_frame) { - CHECK(alive_); - uptr size = fake_frame->size_minus_one + 1; - uptr size_class = ComputeSizeClass(size); - CHECK(allocated_size_classes_[size_class]); - uptr ptr = (uptr)fake_frame; - CHECK(AddrIsInSizeClass(ptr, size_class)); - CHECK(AddrIsInSizeClass(ptr + size - 1, size_class)); - size_classes_[size_class].FifoPush(fake_frame); +static FakeStack *GetFakeStackFast() { + if (FakeStack *fs = GetTLSFakeStack()) + return fs; + if (!__asan_option_detect_stack_use_after_return) + return 0; + return GetFakeStack(); +} + +ALWAYS_INLINE uptr OnMalloc(uptr class_id, uptr size, uptr real_stack) { + FakeStack *fs = GetFakeStackFast(); + if (!fs) return real_stack; + FakeFrame *ff = fs->Allocate(fs->stack_size_log(), class_id, real_stack); + if (!ff) + return real_stack; // Out of fake stack, return the real one. + uptr ptr = reinterpret_cast(ff); + SetShadow(ptr, size, class_id, 0); + return ptr; } -ALWAYS_INLINE void FakeStack::OnFree(uptr ptr, uptr size, uptr real_stack) { - FakeFrame *fake_frame = (FakeFrame*)ptr; - CHECK_EQ(fake_frame->magic, kRetiredStackFrameMagic); - CHECK_NE(fake_frame->descr, 0); - CHECK_EQ(fake_frame->size_minus_one, size - 1); - PoisonShadow(ptr, size, kAsanStackAfterReturnMagic); +ALWAYS_INLINE void OnFree(uptr ptr, uptr class_id, uptr size, uptr real_stack) { + if (ptr == real_stack) + return; + FakeStack::Deallocate(ptr, class_id); + SetShadow(ptr, size, class_id, kMagic8); } } // namespace __asan // ---------------------- Interface ---------------- {{{1 -using namespace __asan; // NOLINT - -uptr __asan_stack_malloc(uptr size, uptr real_stack) { - if (!flags()->use_fake_stack) return real_stack; - AsanThread *t = GetCurrentThread(); - if (!t) { - // TSD is gone, use the real stack. - return real_stack; +#define DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(class_id) \ + extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr \ + __asan_stack_malloc_##class_id(uptr size, uptr real_stack) { \ + return __asan::OnMalloc(class_id, size, real_stack); \ + } \ + extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __asan_stack_free_##class_id( \ + uptr ptr, uptr size, uptr real_stack) { \ + __asan::OnFree(ptr, class_id, size, real_stack); \ } - uptr ptr = t->fake_stack().AllocateStack(size, real_stack); - // Printf("__asan_stack_malloc %p %zu %p\n", ptr, size, real_stack); - return ptr; -} -void __asan_stack_free(uptr ptr, uptr size, uptr real_stack) { - if (!flags()->use_fake_stack) return; - if (ptr != real_stack) { - FakeStack::OnFree(ptr, size, real_stack); - } -} +DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(0) +DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(1) +DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(2) +DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(3) +DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(4) +DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(5) +DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(6) +DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(7) +DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(8) +DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(9) +DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(10) diff --git a/lib/asan/asan_fake_stack.h b/lib/asan/asan_fake_stack.h index 308b4c571832..f17ee0268917 100644 --- a/lib/asan/asan_fake_stack.h +++ b/lib/asan/asan_fake_stack.h @@ -9,12 +9,14 @@ // // This file is a part of AddressSanitizer, an address sanity checker. // -// ASan-private header for asan_fake_stack.cc +// ASan-private header for asan_fake_stack.cc, implements FakeStack. //===----------------------------------------------------------------------===// #ifndef ASAN_FAKE_STACK_H #define ASAN_FAKE_STACK_H +#include "sanitizer_common/sanitizer_common.h" + namespace __asan { // Fake stack frame contains local variables of one function. @@ -22,96 +24,148 @@ struct FakeFrame { uptr magic; // Modified by the instrumented code. uptr descr; // Modified by the instrumented code. uptr pc; // Modified by the instrumented code. - u64 real_stack : 48; - u64 size_minus_one : 16; - // End of the first 32 bytes. - // The rest should not be used when the frame is active. - FakeFrame *next; -}; - -struct FakeFrameFifo { - public: - void FifoPush(FakeFrame *node); - FakeFrame *FifoPop(); - private: - FakeFrame *first_, *last_; -}; - -template -class FakeFrameLifo { - public: - explicit FakeFrameLifo(LinkerInitialized) {} - FakeFrameLifo() : n_frames_(0) {} - void LifoPush(FakeFrame *node) { - CHECK_LT(n_frames_, kMaxNumberOfFrames); - frames_[n_frames_++] = node; - } - void LifoPop() { - CHECK(n_frames_); - n_frames_--; - } - FakeFrame *top() { - if (n_frames_ == 0) - return 0; - return frames_[n_frames_ - 1]; - } - private: - uptr n_frames_; - FakeFrame *frames_[kMaxNumberOfFrames]; + uptr real_stack; }; // For each thread we create a fake stack and place stack objects on this fake // stack instead of the real stack. The fake stack is not really a stack but // a fast malloc-like allocator so that when a function exits the fake stack -// is not poped but remains there for quite some time until gets used again. +// is not popped but remains there for quite some time until gets used again. // So, we poison the objects on the fake stack when function returns. // It helps us find use-after-return bugs. -// We can not rely on __asan_stack_free being called on every function exit, -// so we maintain a lifo list of all current fake frames and update it on every -// call to __asan_stack_malloc. +// +// The FakeStack objects is allocated by a single mmap call and has no other +// pointers. The size of the fake stack depends on the actual thread stack size +// and thus can not be a constant. +// stack_size is a power of two greater or equal to the thread's stack size; +// we store it as its logarithm (stack_size_log). +// FakeStack has kNumberOfSizeClasses (11) size classes, each size class +// is a power of two, starting from 64 bytes. Each size class occupies +// stack_size bytes and thus can allocate +// NumberOfFrames=(stack_size/BytesInSizeClass) fake frames (also a power of 2). +// For each size class we have NumberOfFrames allocation flags, +// each flag indicates whether the given frame is currently allocated. +// All flags for size classes 0 .. 10 are stored in a single contiguous region +// followed by another contiguous region which contains the actual memory for +// size classes. The addresses are computed by GetFlags and GetFrame without +// any memory accesses solely based on 'this' and stack_size_log. +// Allocate() flips the appropriate allocation flag atomically, thus achieving +// async-signal safety. +// This allocator does not have quarantine per se, but it tries to allocate the +// frames in round robin fasion to maximize the delay between a deallocation +// and the next allocation. class FakeStack { - public: - FakeStack(); - explicit FakeStack(LinkerInitialized x) : call_stack_(x) {} - void Init(uptr stack_size); - void StopUsingFakeStack() { alive_ = false; } - void Cleanup(); - uptr AllocateStack(uptr size, uptr real_stack); - static void OnFree(uptr ptr, uptr size, uptr real_stack); - // Return the bottom of the maped region. - uptr AddrIsInFakeStack(uptr addr); - bool StackSize() { return stack_size_; } - - private: - static const uptr kMinStackFrameSizeLog = 9; // Min frame is 512B. + static const uptr kMinStackFrameSizeLog = 6; // Min frame is 64B. static const uptr kMaxStackFrameSizeLog = 16; // Max stack frame is 64K. - static const uptr kMaxStackMallocSize = 1 << kMaxStackFrameSizeLog; + + public: static const uptr kNumberOfSizeClasses = - kMaxStackFrameSizeLog - kMinStackFrameSizeLog + 1; - static const uptr kMaxRecursionDepth = 1023; + kMaxStackFrameSizeLog - kMinStackFrameSizeLog + 1; + + // CTOR: create the FakeStack as a single mmap-ed object. + static FakeStack *Create(uptr stack_size_log); + + void Destroy(); + + // stack_size_log is at least 15 (stack_size >= 32K). + static uptr SizeRequiredForFlags(uptr stack_size_log) { + return 1UL << (stack_size_log + 1 - kMinStackFrameSizeLog); + } - bool AddrIsInSizeClass(uptr addr, uptr size_class); + // Each size class occupies stack_size bytes. + static uptr SizeRequiredForFrames(uptr stack_size_log) { + return (1ULL << stack_size_log) * kNumberOfSizeClasses; + } + + // Number of bytes requires for the whole object. + static uptr RequiredSize(uptr stack_size_log) { + return kFlagsOffset + SizeRequiredForFlags(stack_size_log) + + SizeRequiredForFrames(stack_size_log); + } + + // Offset of the given flag from the first flag. + // The flags for class 0 begin at offset 000000000 + // The flags for class 1 begin at offset 100000000 + // ....................2................ 110000000 + // ....................3................ 111000000 + // and so on. + static uptr FlagsOffset(uptr stack_size_log, uptr class_id) { + uptr t = kNumberOfSizeClasses - 1 - class_id; + const uptr all_ones = (1 << (kNumberOfSizeClasses - 1)) - 1; + return ((all_ones >> t) << t) << (stack_size_log - 15); + } + + static uptr NumberOfFrames(uptr stack_size_log, uptr class_id) { + return 1UL << (stack_size_log - kMinStackFrameSizeLog - class_id); + } + + // Divide n by the numbe of frames in size class. + static uptr ModuloNumberOfFrames(uptr stack_size_log, uptr class_id, uptr n) { + return n & (NumberOfFrames(stack_size_log, class_id) - 1); + } + + // The the pointer to the flags of the given class_id. + u8 *GetFlags(uptr stack_size_log, uptr class_id) { + return reinterpret_cast(this) + kFlagsOffset + + FlagsOffset(stack_size_log, class_id); + } + + // Get frame by class_id and pos. + u8 *GetFrame(uptr stack_size_log, uptr class_id, uptr pos) { + return reinterpret_cast(this) + kFlagsOffset + + SizeRequiredForFlags(stack_size_log) + + (1 << stack_size_log) * class_id + BytesInSizeClass(class_id) * pos; + } + + // Allocate the fake frame. + FakeFrame *Allocate(uptr stack_size_log, uptr class_id, uptr real_stack); + + // Deallocate the fake frame: read the saved flag address and write 0 there. + static void Deallocate(uptr x, uptr class_id) { + **SavedFlagPtr(x, class_id) = 0; + } + + // Poison the entire FakeStack's shadow with the magic value. + void PoisonAll(u8 magic); + + // Return the beginning of the FakeFrame or 0 if the address is not ours. + uptr AddrIsInFakeStack(uptr addr); - // Each size class should be large enough to hold all frames. - uptr ClassMmapSize(uptr size_class); + // Number of bytes in a fake frame of this size class. + static uptr BytesInSizeClass(uptr class_id) { + return 1UL << (class_id + kMinStackFrameSizeLog); + } - uptr ClassSize(uptr size_class) { - return 1UL << (size_class + kMinStackFrameSizeLog); + // The fake frame is guaranteed to have a right redzone. + // We use the last word of that redzone to store the address of the flag + // that corresponds to the current frame to make faster deallocation. + static u8 **SavedFlagPtr(uptr x, uptr class_id) { + return reinterpret_cast(x + BytesInSizeClass(class_id) - sizeof(x)); } - void DeallocateFrame(FakeFrame *fake_frame); + uptr stack_size_log() const { return stack_size_log_; } + + void HandleNoReturn(); + void GC(uptr real_stack); - uptr ComputeSizeClass(uptr alloc_size); - void AllocateOneSizeClass(uptr size_class); + void ForEachFakeFrame(RangeIteratorCallback callback, void *arg); - uptr stack_size_; - bool alive_; + private: + FakeStack() { } + static const uptr kFlagsOffset = 4096; // This is were the flags begin. + // Must match the number of uses of DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID + COMPILER_CHECK(kNumberOfSizeClasses == 11); + static const uptr kMaxStackMallocSize = 1 << kMaxStackFrameSizeLog; - uptr allocated_size_classes_[kNumberOfSizeClasses]; - FakeFrameFifo size_classes_[kNumberOfSizeClasses]; - FakeFrameLifo call_stack_; + uptr hint_position_[kNumberOfSizeClasses]; + uptr stack_size_log_; + // a bit is set if something was allocated from the corresponding size class. + bool needs_gc_; }; +FakeStack *GetTLSFakeStack(); +void SetTLSFakeStack(FakeStack *fs); + } // namespace __asan #endif // ASAN_FAKE_STACK_H diff --git a/lib/asan/asan_flags.h b/lib/asan/asan_flags.h index 2f3bc9051ae1..89662f28b29c 100644 --- a/lib/asan/asan_flags.h +++ b/lib/asan/asan_flags.h @@ -32,8 +32,6 @@ struct Flags { // Lower value may reduce memory usage but increase the chance of // false negatives. int quarantine_size; - // Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output). - int verbosity; // Size (in bytes) of redzones around heap objects. // Requirement: redzone >= 32, is a power of two. int redzone; @@ -52,8 +50,10 @@ struct Flags { bool replace_intrin; // Used on Mac only. bool mac_ignore_invalid_free; - // ASan allocator flag. - bool use_fake_stack; + // Enables stack-use-after-return checking at run-time. + bool detect_stack_use_after_return; + // The minimal fake stack size log. + int uar_stack_size_log; // ASan allocator flag. max_malloc_fill_size is the maximal amount of bytes // that will be filled with malloc_fill_byte on malloc. int max_malloc_fill_size, malloc_fill_byte; @@ -83,6 +83,9 @@ struct Flags { bool print_legend; // If set, prints ASan exit stats even after program terminates successfully. bool atexit; + // If set, coverage information will be dumped at shutdown time if the + // appropriate instrumentation was enabled. + bool coverage; // By default, disable core dumper on 64-bit - it makes little sense // to dump 16T+ core. bool disable_core; @@ -93,23 +96,20 @@ struct Flags { // but also thread creation stacks for threads that created those threads, // etc. up to main thread. bool print_full_thread_history; - // ASan will write logs to "log_path.pid" instead of stderr. - const char *log_path; // Poison (or not) the heap memory on [de]allocation. Zero value is useful // for benchmarking the allocator or instrumentator. bool poison_heap; + // If true, poison partially addressable 8-byte aligned words (default=true). + // This flag affects heap and global buffers, but not stack buffers. + bool poison_partial; // Report errors on malloc/delete, new/free, new/delete[], etc. bool alloc_dealloc_mismatch; - // Use stack depot instead of storing stacks in the redzones. - bool use_stack_depot; // If true, assume that memcmp(p1, p2, n) always reads n bytes before // comparing p1 and p2. bool strict_memcmp; // If true, assume that dynamic initializers can never access globals from // other modules, even if the latter are already initialized. bool strict_init_order; - // Invoke LeakSanitizer at process exit. - bool detect_leaks; }; extern Flags asan_flags_dont_use_directly; diff --git a/lib/asan/asan_globals.cc b/lib/asan/asan_globals.cc index 301ea44f2ca5..81699676b574 100644 --- a/lib/asan/asan_globals.cc +++ b/lib/asan/asan_globals.cc @@ -41,7 +41,7 @@ struct DynInitGlobal { Global g; bool initialized; }; -typedef InternalVector VectorOfGlobals; +typedef InternalMmapVector VectorOfGlobals; // Lazy-initialized and never deleted. static VectorOfGlobals *dynamic_init_globals; @@ -94,15 +94,13 @@ static void RegisterGlobal(const Global *g) { CHECK(AddrIsAlignedByGranularity(g->size_with_redzone)); if (flags()->poison_heap) PoisonRedZones(*g); - ListOfGlobals *l = - (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals)); + ListOfGlobals *l = new(allocator_for_globals) ListOfGlobals; l->g = g; l->next = list_of_all_globals; list_of_all_globals = l; if (g->has_dynamic_init) { if (dynamic_init_globals == 0) { - void *mem = allocator_for_globals.Allocate(sizeof(VectorOfGlobals)); - dynamic_init_globals = new(mem) + dynamic_init_globals = new(allocator_for_globals) VectorOfGlobals(kDynamicInitGlobalsInitialCapacity); } DynInitGlobal dyn_global = { *g, false }; diff --git a/lib/asan/asan_intercepted_functions.h b/lib/asan/asan_intercepted_functions.h index 842781cdb17f..de42cd6d5ca6 100644 --- a/lib/asan/asan_intercepted_functions.h +++ b/lib/asan/asan_intercepted_functions.h @@ -14,15 +14,8 @@ #ifndef ASAN_INTERCEPTED_FUNCTIONS_H #define ASAN_INTERCEPTED_FUNCTIONS_H -#include "asan_internal.h" -#include "interception/interception.h" #include "sanitizer_common/sanitizer_platform_interceptors.h" -#include -#include - -using __sanitizer::uptr; - // Use macro to describe if specific function should be // intercepted on a given platform. #if !SANITIZER_WINDOWS @@ -83,32 +76,4 @@ using __sanitizer::uptr; # define ASAN_INTERCEPT___CXA_ATEXIT 0 #endif -# if SANITIZER_WINDOWS -extern "C" { -// Windows threads. -__declspec(dllimport) -void* __stdcall CreateThread(void *sec, uptr st, void* start, - void *arg, DWORD fl, DWORD *id); - -int memcmp(const void *a1, const void *a2, uptr size); -void memmove(void *to, const void *from, uptr size); -void* memset(void *block, int c, uptr size); -void* memcpy(void *to, const void *from, uptr size); -char* strcat(char *to, const char* from); // NOLINT -char* strchr(const char *str, int c); -int strcmp(const char *s1, const char* s2); -char* strcpy(char *to, const char* from); // NOLINT -uptr strlen(const char *s); -char* strncat(char *to, const char* from, uptr size); -int strncmp(const char *s1, const char* s2, uptr size); -char* strncpy(char *to, const char* from, uptr size); -uptr strnlen(const char *s, uptr maxlen); -int atoi(const char *nptr); -long atol(const char *nptr); // NOLINT -long strtol(const char *nptr, char **endptr, int base); // NOLINT -void longjmp(void *env, int value); -double frexp(double x, int *expptr); -} -# endif - #endif // ASAN_INTERCEPTED_FUNCTIONS_H diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc index 7e7deea29634..a25827b6b9ae 100644 --- a/lib/asan/asan_interceptors.cc +++ b/lib/asan/asan_interceptors.cc @@ -53,7 +53,7 @@ static inline bool QuickCheckForUnpoisonedRegion(uptr beg, uptr size) { } while (0) #define ASAN_READ_RANGE(offset, size) ACCESS_MEMORY_RANGE(offset, size, false) -#define ASAN_WRITE_RANGE(offset, size) ACCESS_MEMORY_RANGE(offset, size, true); +#define ASAN_WRITE_RANGE(offset, size) ACCESS_MEMORY_RANGE(offset, size, true) // Behavior of functions like "memcpy" or "strcpy" is undefined // if memory intervals overlap. We report error in this case. @@ -94,9 +94,9 @@ void SetThreadName(const char *name) { asanThreadRegistry().SetThreadName(t->tid(), name); } -static void DisableStrictInitOrderChecker() { - if (flags()->strict_init_order) - flags()->check_initialization_order = false; +int OnExit() { + // FIXME: ask frontend whether we need to return failure. + return 0; } } // namespace __asan @@ -104,26 +104,69 @@ static void DisableStrictInitOrderChecker() { // ---------------------- Wrappers ---------------- {{{1 using namespace __asan; // NOLINT +DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr) +DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) + +#if !SANITIZER_MAC +#define ASAN_INTERCEPT_FUNC(name) \ + do { \ + if ((!INTERCEPT_FUNCTION(name) || !REAL(name)) && \ + common_flags()->verbosity > 0) \ + Report("AddressSanitizer: failed to intercept '" #name "'\n"); \ + } while (0) +#else +// OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION. +#define ASAN_INTERCEPT_FUNC(name) +#endif // SANITIZER_MAC + +#define COMMON_INTERCEPT_FUNCTION(name) ASAN_INTERCEPT_FUNC(name) +#define COMMON_INTERCEPTOR_UNPOISON_PARAM(ctx, count) \ + do { \ + } while (false) #define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \ ASAN_WRITE_RANGE(ptr, size) #define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) ASAN_READ_RANGE(ptr, size) -#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \ - do { \ - if (asan_init_is_running) \ - return REAL(func)(__VA_ARGS__); \ - ctx = 0; \ - (void)ctx; \ - ENSURE_ASAN_INITED(); \ +#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \ + do { \ + if (asan_init_is_running) return REAL(func)(__VA_ARGS__); \ + ctx = 0; \ + (void) ctx; \ + if (SANITIZER_MAC && !asan_inited) return REAL(func)(__VA_ARGS__); \ + ENSURE_ASAN_INITED(); \ + } while (false) +#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \ + do { \ + } while (false) +#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \ + do { \ + } while (false) +#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \ + do { \ } while (false) -#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) do { } while (false) -#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) do { } while (false) #define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) SetThreadName(name) +// Should be asanThreadRegistry().SetThreadNameByUserId(thread, name) +// But asan does not remember UserId's for threads (pthread_t); +// and remembers all ever existed threads, so the linear search by UserId +// can be slow. +#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \ + do { \ + } while (false) +#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name) +#define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit() #include "sanitizer_common/sanitizer_common_interceptors.inc" #define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(p, s) #define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) ASAN_WRITE_RANGE(p, s) -#define COMMON_SYSCALL_POST_READ_RANGE(p, s) -#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) +#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \ + do { \ + (void)(p); \ + (void)(s); \ + } while (false) +#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \ + do { \ + (void)(p); \ + (void)(s); \ + } while (false) #include "sanitizer_common/sanitizer_common_syscalls.inc" static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { @@ -133,16 +176,16 @@ static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { } #if ASAN_INTERCEPT_PTHREAD_CREATE -extern "C" int pthread_attr_getdetachstate(void *attr, int *v); - INTERCEPTOR(int, pthread_create, void *thread, void *attr, void *(*start_routine)(void*), void *arg) { + EnsureMainThreadIDIsCorrect(); // Strict init-order checking in thread-hostile. - DisableStrictInitOrderChecker(); + if (flags()->strict_init_order) + StopInitOrderChecking(); GET_STACK_TRACE_THREAD; int detached = 0; if (attr != 0) - pthread_attr_getdetachstate(attr, &detached); + REAL(pthread_attr_getdetachstate)(attr, &detached); u32 current_tid = GetCurrentTidOrInvalid(); AsanThread *t = AsanThread::Create(start_routine, arg); @@ -170,7 +213,7 @@ INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act, #elif SANITIZER_POSIX // We need to have defined REAL(sigaction) on posix systems. DEFINE_REAL(int, sigaction, int signum, const struct sigaction *act, - struct sigaction *oldact); + struct sigaction *oldact) #endif // ASAN_INTERCEPT_SIGNAL_AND_SIGACTION #if ASAN_INTERCEPT_SWAPCONTEXT @@ -240,13 +283,15 @@ INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) { // Since asan maps 16T of RAM, mlock is completely unfriendly to asan. // All functions return 0 (success). static void MlockIsUnsupported() { - static bool printed = 0; + static bool printed = false; if (printed) return; printed = true; - Printf("INFO: AddressSanitizer ignores mlock/mlockall/munlock/munlockall\n"); + if (common_flags()->verbosity > 0) { + Printf("INFO: AddressSanitizer ignores " + "mlock/mlockall/munlock/munlockall\n"); + } } -extern "C" { INTERCEPTOR(int, mlock, const void *addr, uptr len) { MlockIsUnsupported(); return 0; @@ -266,7 +311,6 @@ INTERCEPTOR(int, munlockall, void) { MlockIsUnsupported(); return 0; } -} // extern "C" static inline int CharCmp(unsigned char c1, unsigned char c2) { return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1; @@ -300,7 +344,23 @@ INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) { return REAL(memcmp(a1, a2, size)); } +#define MEMMOVE_BODY { \ + if (!asan_inited) return internal_memmove(to, from, size); \ + if (asan_init_is_running) { \ + return REAL(memmove)(to, from, size); \ + } \ + ENSURE_ASAN_INITED(); \ + if (flags()->replace_intrin) { \ + ASAN_READ_RANGE(from, size); \ + ASAN_WRITE_RANGE(to, size); \ + } \ + return internal_memmove(to, from, size); \ +} + +INTERCEPTOR(void*, memmove, void *to, const void *from, uptr size) MEMMOVE_BODY + INTERCEPTOR(void*, memcpy, void *to, const void *from, uptr size) { +#if !SANITIZER_MAC if (!asan_inited) return internal_memcpy(to, from, size); // memcpy is called during __asan_init() from the internals // of printf(...). @@ -317,24 +377,19 @@ INTERCEPTOR(void*, memcpy, void *to, const void *from, uptr size) { ASAN_READ_RANGE(from, size); ASAN_WRITE_RANGE(to, size); } - // Interposing of resolver functions is broken on Mac OS 10.7 and 10.8. + // Interposing of resolver functions is broken on Mac OS 10.7 and 10.8, so + // calling REAL(memcpy) here leads to infinite recursion. // See also http://code.google.com/p/address-sanitizer/issues/detail?id=116. return internal_memcpy(to, from, size); -} - -INTERCEPTOR(void*, memmove, void *to, const void *from, uptr size) { - if (!asan_inited) return internal_memmove(to, from, size); - if (asan_init_is_running) { - return REAL(memmove)(to, from, size); - } - ENSURE_ASAN_INITED(); - if (flags()->replace_intrin) { - ASAN_READ_RANGE(from, size); - ASAN_WRITE_RANGE(to, size); - } - // Interposing of resolver functions is broken on Mac OS 10.7 and 10.8. - // See also http://code.google.com/p/address-sanitizer/issues/detail?id=116. - return internal_memmove(to, from, size); +#else + // At least on 10.7 and 10.8 both memcpy() and memmove() are being replaced + // with WRAP(memcpy). As a result, false positives are reported for memmove() + // calls. If we just disable error reporting with + // ASAN_OPTIONS=replace_intrin=0, memmove() is still replaced with + // internal_memcpy(), which may lead to crashes, see + // http://llvm.org/bugs/show_bug.cgi?id=16362. + MEMMOVE_BODY +#endif // !SANITIZER_MAC } INTERCEPTOR(void*, memset, void *block, int c, uptr size) { @@ -375,7 +430,7 @@ INTERCEPTOR(char*, index, const char *string, int c) DECLARE_REAL(char*, index, const char *string, int c) OVERRIDE_FUNCTION(index, strchr); # else -DEFINE_REAL(char*, index, const char *string, int c); +DEFINE_REAL(char*, index, const char *string, int c) # endif # endif #endif // ASAN_INTERCEPT_INDEX @@ -418,24 +473,6 @@ INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) { return REAL(strncat)(to, from, size); } -INTERCEPTOR(int, strcmp, const char *s1, const char *s2) { - if (!asan_inited) return internal_strcmp(s1, s2); - if (asan_init_is_running) { - return REAL(strcmp)(s1, s2); - } - ENSURE_ASAN_INITED(); - unsigned char c1, c2; - uptr i; - for (i = 0; ; i++) { - c1 = (unsigned char)s1[i]; - c2 = (unsigned char)s2[i]; - if (c1 != c2 || c1 == '\0') break; - } - ASAN_READ_RANGE(s1, i + 1); - ASAN_READ_RANGE(s2, i + 1); - return CharCmp(c1, c2); -} - INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT #if SANITIZER_MAC if (!asan_inited) return REAL(strcpy)(to, from); // NOLINT @@ -457,21 +494,16 @@ INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT #if ASAN_INTERCEPT_STRDUP INTERCEPTOR(char*, strdup, const char *s) { -#if SANITIZER_MAC - // FIXME: because internal_strdup() uses InternalAlloc(), which currently - // just calls malloc() on Mac, we can't use internal_strdup() with the - // dynamic runtime. We can remove the call to REAL(strdup) once InternalAlloc - // starts using mmap() instead. - // See also http://code.google.com/p/address-sanitizer/issues/detail?id=123. - if (!asan_inited) return REAL(strdup)(s); -#endif if (!asan_inited) return internal_strdup(s); ENSURE_ASAN_INITED(); + uptr length = REAL(strlen)(s); if (flags()->replace_str) { - uptr length = REAL(strlen)(s); ASAN_READ_RANGE(s, length + 1); } - return REAL(strdup)(s); + GET_STACK_TRACE_MALLOC; + void *new_mem = asan_malloc(length + 1, &stack); + REAL(memcpy)(new_mem, s, length + 1); + return reinterpret_cast(new_mem); } #endif @@ -490,24 +522,13 @@ INTERCEPTOR(uptr, strlen, const char *s) { return length; } -INTERCEPTOR(int, strncmp, const char *s1, const char *s2, uptr size) { - if (!asan_inited) return internal_strncmp(s1, s2, size); - // strncmp is called from malloc_default_purgeable_zone() - // in __asan::ReplaceSystemAlloc() on Mac. - if (asan_init_is_running) { - return REAL(strncmp)(s1, s2, size); +INTERCEPTOR(uptr, wcslen, const wchar_t *s) { + uptr length = REAL(wcslen)(s); + if (!asan_init_is_running) { + ENSURE_ASAN_INITED(); + ASAN_READ_RANGE(s, (length + 1) * sizeof(wchar_t)); } - ENSURE_ASAN_INITED(); - unsigned char c1 = 0, c2 = 0; - uptr i; - for (i = 0; i < size; i++) { - c1 = (unsigned char)s1[i]; - c2 = (unsigned char)s2[i]; - if (c1 != c2 || c1 == '\0') break; - } - ASAN_READ_RANGE(s1, Min(i + 1, size)); - ASAN_READ_RANGE(s2, Min(i + 1, size)); - return CharCmp(c1, c2); + return length; } INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) { @@ -644,6 +665,9 @@ static void AtCxaAtexit(void *unused) { #if ASAN_INTERCEPT___CXA_ATEXIT INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg, void *dso_handle) { +#if SANITIZER_MAC + if (!asan_inited) return REAL(__cxa_atexit)(func, arg, dso_handle); +#endif ENSURE_ASAN_INITED(); int res = REAL(__cxa_atexit)(func, arg, dso_handle); REAL(__cxa_atexit)(AtCxaAtexit, 0, 0); @@ -651,26 +675,22 @@ INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg, } #endif // ASAN_INTERCEPT___CXA_ATEXIT -#define ASAN_INTERCEPT_FUNC(name) do { \ - if (!INTERCEPT_FUNCTION(name) && flags()->verbosity > 0) \ - Report("AddressSanitizer: failed to intercept '" #name "'\n"); \ - } while (0) - #if SANITIZER_WINDOWS INTERCEPTOR_WINAPI(DWORD, CreateThread, void* security, uptr stack_size, DWORD (__stdcall *start_routine)(void*), void* arg, - DWORD flags, void* tid) { + DWORD thr_flags, void* tid) { // Strict init-order checking in thread-hostile. - DisableStrictInitOrderChecker(); + if (flags()->strict_init_order) + StopInitOrderChecking(); GET_STACK_TRACE_THREAD; u32 current_tid = GetCurrentTidOrInvalid(); AsanThread *t = AsanThread::Create(start_routine, arg); CreateThreadContextArgs args = { t, &stack }; - int detached = 0; // FIXME: how can we determine it on Windows? + bool detached = false; // FIXME: how can we determine it on Windows? asanThreadRegistry().CreateThread(*(uptr*)t, detached, current_tid, &args); return REAL(CreateThread)(security, stack_size, - asan_thread_start, t, flags, tid); + asan_thread_start, t, thr_flags, tid); } namespace __asan { @@ -687,9 +707,6 @@ void InitializeAsanInterceptors() { static bool was_called_once; CHECK(was_called_once == false); was_called_once = true; -#if SANITIZER_MAC - return; -#else SANITIZER_COMMON_INTERCEPTORS_INIT; // Intercept mem* functions. @@ -703,11 +720,10 @@ void InitializeAsanInterceptors() { // Intercept str* functions. ASAN_INTERCEPT_FUNC(strcat); // NOLINT ASAN_INTERCEPT_FUNC(strchr); - ASAN_INTERCEPT_FUNC(strcmp); ASAN_INTERCEPT_FUNC(strcpy); // NOLINT ASAN_INTERCEPT_FUNC(strlen); + ASAN_INTERCEPT_FUNC(wcslen); ASAN_INTERCEPT_FUNC(strncat); - ASAN_INTERCEPT_FUNC(strncmp); ASAN_INTERCEPT_FUNC(strncpy); #if ASAN_INTERCEPT_STRDUP ASAN_INTERCEPT_FUNC(strdup); @@ -771,10 +787,9 @@ void InitializeAsanInterceptors() { InitializeWindowsInterceptors(); #endif - if (flags()->verbosity > 0) { + if (common_flags()->verbosity > 0) { Report("AddressSanitizer: libc interceptors initialized\n"); } -#endif // SANITIZER_MAC } } // namespace __asan diff --git a/lib/asan/asan_interface_internal.h b/lib/asan/asan_interface_internal.h index 24f76253bccd..5c1d025296fb 100644 --- a/lib/asan/asan_interface_internal.h +++ b/lib/asan/asan_interface_internal.h @@ -30,7 +30,7 @@ extern "C" { // v2=>v3: stack frame description (created by the compiler) // contains the function PC as the 3-rd field (see // DescribeAddressIfStack). - void __asan_init_v3() SANITIZER_INTERFACE_ATTRIBUTE; + SANITIZER_INTERFACE_ATTRIBUTE void __asan_init_v3(); #define __asan_init __asan_init_v3 // This structure describes an instrumented global variable. @@ -46,96 +46,85 @@ extern "C" { // These two functions should be called by the instrumented code. // 'globals' is an array of structures describing 'n' globals. - void __asan_register_globals(__asan_global *globals, uptr n) - SANITIZER_INTERFACE_ATTRIBUTE; - void __asan_unregister_globals(__asan_global *globals, uptr n) - SANITIZER_INTERFACE_ATTRIBUTE; + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_register_globals(__asan_global *globals, uptr n); + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_unregister_globals(__asan_global *globals, uptr n); // These two functions should be called before and after dynamic initializers // of a single module run, respectively. - void __asan_before_dynamic_init(const char *module_name) - SANITIZER_INTERFACE_ATTRIBUTE; - void __asan_after_dynamic_init() - SANITIZER_INTERFACE_ATTRIBUTE; - - // These two functions are used by the instrumented code in the - // use-after-return mode. __asan_stack_malloc allocates size bytes of - // fake stack and __asan_stack_free poisons it. real_stack is a pointer to - // the real stack region. - uptr __asan_stack_malloc(uptr size, uptr real_stack) - SANITIZER_INTERFACE_ATTRIBUTE; - void __asan_stack_free(uptr ptr, uptr size, uptr real_stack) - SANITIZER_INTERFACE_ATTRIBUTE; + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_before_dynamic_init(const char *module_name); + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_after_dynamic_init(); // These two functions are used by instrumented code in the // use-after-scope mode. They mark memory for local variables as // unaddressable when they leave scope and addressable before the // function exits. - void __asan_poison_stack_memory(uptr addr, uptr size) - SANITIZER_INTERFACE_ATTRIBUTE; - void __asan_unpoison_stack_memory(uptr addr, uptr size) - SANITIZER_INTERFACE_ATTRIBUTE; + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_poison_stack_memory(uptr addr, uptr size); + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_unpoison_stack_memory(uptr addr, uptr size); // Performs cleanup before a NoReturn function. Must be called before things // like _exit and execl to avoid false positives on stack. - void __asan_handle_no_return() SANITIZER_INTERFACE_ATTRIBUTE; + SANITIZER_INTERFACE_ATTRIBUTE void __asan_handle_no_return(); - void __asan_poison_memory_region(void const volatile *addr, uptr size) - SANITIZER_INTERFACE_ATTRIBUTE; - void __asan_unpoison_memory_region(void const volatile *addr, uptr size) - SANITIZER_INTERFACE_ATTRIBUTE; + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_poison_memory_region(void const volatile *addr, uptr size); + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_unpoison_memory_region(void const volatile *addr, uptr size); - bool __asan_address_is_poisoned(void const volatile *addr) - SANITIZER_INTERFACE_ATTRIBUTE; + SANITIZER_INTERFACE_ATTRIBUTE + bool __asan_address_is_poisoned(void const volatile *addr); - uptr __asan_region_is_poisoned(uptr beg, uptr size) - SANITIZER_INTERFACE_ATTRIBUTE; + SANITIZER_INTERFACE_ATTRIBUTE + uptr __asan_region_is_poisoned(uptr beg, uptr size); - void __asan_describe_address(uptr addr) - SANITIZER_INTERFACE_ATTRIBUTE; + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_describe_address(uptr addr); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_report_error(uptr pc, uptr bp, uptr sp, - uptr addr, bool is_write, uptr access_size) - SANITIZER_INTERFACE_ATTRIBUTE; + uptr addr, bool is_write, uptr access_size); - int __asan_set_error_exit_code(int exit_code) - SANITIZER_INTERFACE_ATTRIBUTE; - void __asan_set_death_callback(void (*callback)(void)) - SANITIZER_INTERFACE_ATTRIBUTE; - void __asan_set_error_report_callback(void (*callback)(const char*)) - SANITIZER_INTERFACE_ATTRIBUTE; + SANITIZER_INTERFACE_ATTRIBUTE + int __asan_set_error_exit_code(int exit_code); + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_set_death_callback(void (*callback)(void)); + SANITIZER_INTERFACE_ATTRIBUTE + void __asan_set_error_report_callback(void (*callback)(const char*)); - /* OPTIONAL */ void __asan_on_error() - SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE; + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + /* OPTIONAL */ void __asan_on_error(); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE /* OPTIONAL */ bool __asan_symbolize(const void *pc, char *out_buffer, - int out_size) - SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE; - - uptr __asan_get_estimated_allocated_size(uptr size) - SANITIZER_INTERFACE_ATTRIBUTE; - bool __asan_get_ownership(const void *p) - SANITIZER_INTERFACE_ATTRIBUTE; - uptr __asan_get_allocated_size(const void *p) - SANITIZER_INTERFACE_ATTRIBUTE; - uptr __asan_get_current_allocated_bytes() - SANITIZER_INTERFACE_ATTRIBUTE; - uptr __asan_get_heap_size() - SANITIZER_INTERFACE_ATTRIBUTE; - uptr __asan_get_free_bytes() - SANITIZER_INTERFACE_ATTRIBUTE; - uptr __asan_get_unmapped_bytes() - SANITIZER_INTERFACE_ATTRIBUTE; - void __asan_print_accumulated_stats() - SANITIZER_INTERFACE_ATTRIBUTE; - - /* OPTIONAL */ const char* __asan_default_options() - SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE; - - /* OPTIONAL */ void __asan_malloc_hook(void *ptr, uptr size) - SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE; - /* OPTIONAL */ void __asan_free_hook(void *ptr) - SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE; + int out_size); + + SANITIZER_INTERFACE_ATTRIBUTE + uptr __asan_get_estimated_allocated_size(uptr size); + + SANITIZER_INTERFACE_ATTRIBUTE bool __asan_get_ownership(const void *p); + SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_allocated_size(const void *p); + SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_current_allocated_bytes(); + SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_heap_size(); + SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_free_bytes(); + SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_get_unmapped_bytes(); + SANITIZER_INTERFACE_ATTRIBUTE void __asan_print_accumulated_stats(); + + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + /* OPTIONAL */ const char* __asan_default_options(); + + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + /* OPTIONAL */ void __asan_malloc_hook(void *ptr, uptr size); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + /* OPTIONAL */ void __asan_free_hook(void *ptr); + + // Global flag, copy of ASAN_OPTIONS=detect_stack_use_after_return + SANITIZER_INTERFACE_ATTRIBUTE + extern int __asan_option_detect_stack_use_after_return; } // extern "C" #endif // ASAN_INTERFACE_INTERNAL_H diff --git a/lib/asan/asan_internal.h b/lib/asan/asan_internal.h index 7a4d74472bcd..70e55ea0afef 100644 --- a/lib/asan/asan_internal.h +++ b/lib/asan/asan_internal.h @@ -98,6 +98,7 @@ void StopInitOrderChecking(); void AsanTSDInit(void (*destructor)(void *tsd)); void *AsanTSDGet(); void AsanTSDSet(void *tsd); +void PlatformTSDDtor(void *tsd); void AppendToErrorMessageBuffer(const char *buffer); diff --git a/lib/asan/asan_linux.cc b/lib/asan/asan_linux.cc index 17bb4ca5f01c..39eec3bfd301 100644 --- a/lib/asan/asan_linux.cc +++ b/lib/asan/asan_linux.cc @@ -58,6 +58,12 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { *pc = ucontext->uc_mcontext.arm_pc; *bp = ucontext->uc_mcontext.arm_fp; *sp = ucontext->uc_mcontext.arm_sp; +# elif defined(__hppa__) + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.sc_iaoq[0]; + /* GCC uses %r3 whenever a frame pointer is needed. */ + *bp = ucontext->uc_mcontext.sc_gr[3]; + *sp = ucontext->uc_mcontext.sc_gr[30]; # elif defined(__x86_64__) ucontext_t *ucontext = (ucontext_t*)context; *pc = ucontext->uc_mcontext.gregs[REG_RIP]; @@ -89,6 +95,11 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { stk_ptr = (uptr *) *sp; *bp = stk_ptr[15]; # endif +# elif defined(__mips__) + ucontext_t *ucontext = (ucontext_t*)context; + *pc = ucontext->uc_mcontext.gregs[31]; + *bp = ucontext->uc_mcontext.gregs[30]; + *sp = ucontext->uc_mcontext.gregs[29]; #else # error "Unsupported arch" #endif diff --git a/lib/asan/asan_mac.cc b/lib/asan/asan_mac.cc index 4313534008e7..e27d70adb81e 100644 --- a/lib/asan/asan_mac.cc +++ b/lib/asan/asan_mac.cc @@ -21,6 +21,7 @@ #include "asan_mapping.h" #include "asan_stack.h" #include "asan_thread.h" +#include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_libc.h" #include // for _NSGetArgv @@ -52,7 +53,9 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { # endif // SANITIZER_WORDSIZE } -int GetMacosVersion() { +MacosVersion cached_macos_version = MACOS_VERSION_UNINITIALIZED; + +MacosVersion GetMacosVersionInternal() { int mib[2] = { CTL_KERN, KERN_OSRELEASE }; char version[100]; uptr len = 0, maxlen = sizeof(version) / sizeof(version[0]); @@ -68,6 +71,7 @@ int GetMacosVersion() { case '0': return MACOS_VERSION_SNOW_LEOPARD; case '1': return MACOS_VERSION_LION; case '2': return MACOS_VERSION_MOUNTAIN_LION; + case '3': return MACOS_VERSION_MAVERICKS; default: return MACOS_VERSION_UNKNOWN; } } @@ -75,6 +79,18 @@ int GetMacosVersion() { } } +MacosVersion GetMacosVersion() { + atomic_uint32_t *cache = + reinterpret_cast(&cached_macos_version); + MacosVersion result = + static_cast(atomic_load(cache, memory_order_acquire)); + if (result == MACOS_VERSION_UNINITIALIZED) { + result = GetMacosVersionInternal(); + atomic_store(cache, result, memory_order_release); + } + return result; +} + bool PlatformHasDifferentMemcpyAndMemmove() { // On OS X 10.7 memcpy() and memmove() are both resolved // into memmove$VARIANT$sse42. @@ -158,7 +174,7 @@ void MaybeReexec() { // Set DYLD_INSERT_LIBRARIES equal to the runtime dylib name. setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0); } - if (flags()->verbosity >= 1) { + if (common_flags()->verbosity >= 1) { Report("exec()-ing the program with\n"); Report("%s=%s\n", kDyldInsertLibraries, new_env); Report("to enable ASan wrappers.\n"); @@ -295,7 +311,7 @@ extern "C" void asan_dispatch_call_block_and_release(void *block) { GET_STACK_TRACE_THREAD; asan_block_context_t *context = (asan_block_context_t*)block; - if (flags()->verbosity >= 2) { + if (common_flags()->verbosity >= 2) { Report("asan_dispatch_call_block_and_release(): " "context: %p, pthread_self: %p\n", block, pthread_self()); @@ -330,7 +346,7 @@ asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func, dispatch_function_t func) { \ GET_STACK_TRACE_THREAD; \ asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); \ - if (flags()->verbosity >= 2) { \ + if (common_flags()->verbosity >= 2) { \ Report(#dispatch_x_f "(): context: %p, pthread_self: %p\n", \ asan_ctxt, pthread_self()); \ PRINT_CURRENT_STACK(); \ @@ -348,7 +364,7 @@ INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when, dispatch_function_t func) { GET_STACK_TRACE_THREAD; asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); - if (flags()->verbosity >= 2) { + if (common_flags()->verbosity >= 2) { Report("dispatch_after_f: %p\n", asan_ctxt); PRINT_CURRENT_STACK(); } @@ -361,7 +377,7 @@ INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group, dispatch_function_t func) { GET_STACK_TRACE_THREAD; asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); - if (flags()->verbosity >= 2) { + if (common_flags()->verbosity >= 2) { Report("dispatch_group_async_f(): context: %p, pthread_self: %p\n", asan_ctxt, pthread_self()); PRINT_CURRENT_STACK(); diff --git a/lib/asan/asan_mac.h b/lib/asan/asan_mac.h index b1a1966dbc6e..827b8b001699 100644 --- a/lib/asan/asan_mac.h +++ b/lib/asan/asan_mac.h @@ -12,7 +12,7 @@ // Mac-specific ASan definitions. //===----------------------------------------------------------------------===// #ifndef ASAN_MAC_H -#define ASAN__MAC_H +#define ASAN_MAC_H // CF_RC_BITS, the layout of CFRuntimeBase and __CFStrIsConstant are internal // and subject to change in further CoreFoundation versions. Apple does not @@ -36,12 +36,14 @@ typedef struct __CFRuntimeBase { #endif } CFRuntimeBase; -enum { - MACOS_VERSION_UNKNOWN = 0, +enum MacosVersion { + MACOS_VERSION_UNINITIALIZED = 0, + MACOS_VERSION_UNKNOWN, MACOS_VERSION_LEOPARD, MACOS_VERSION_SNOW_LEOPARD, MACOS_VERSION_LION, - MACOS_VERSION_MOUNTAIN_LION + MACOS_VERSION_MOUNTAIN_LION, + MACOS_VERSION_MAVERICKS }; // Used by asan_malloc_mac.cc and asan_mac.cc @@ -49,7 +51,7 @@ extern "C" void __CFInitialize(); namespace __asan { -int GetMacosVersion(); +MacosVersion GetMacosVersion(); void MaybeReplaceCFAllocator(); } // namespace __asan diff --git a/lib/asan/asan_malloc_linux.cc b/lib/asan/asan_malloc_linux.cc index 20e636b9b3c0..24b7f6977927 100644 --- a/lib/asan/asan_malloc_linux.cc +++ b/lib/asan/asan_malloc_linux.cc @@ -105,8 +105,9 @@ INTERCEPTOR(void*, __libc_memalign, uptr align, uptr s) ALIAS("memalign"); INTERCEPTOR(uptr, malloc_usable_size, void *ptr) { - GET_STACK_TRACE_MALLOC; - return asan_malloc_usable_size(ptr, &stack); + GET_CURRENT_PC_BP_SP; + (void)sp; + return asan_malloc_usable_size(ptr, pc, bp); } // We avoid including malloc.h for portability reasons. diff --git a/lib/asan/asan_malloc_mac.cc b/lib/asan/asan_malloc_mac.cc index 4f353cb99ca7..f9f08f0201c2 100644 --- a/lib/asan/asan_malloc_mac.cc +++ b/lib/asan/asan_malloc_mac.cc @@ -19,6 +19,7 @@ #include #include #include +#include #include "asan_allocator.h" #include "asan_interceptors.h" @@ -42,10 +43,19 @@ INTERCEPTOR(malloc_zone_t *, malloc_create_zone, vm_size_t start_size, unsigned zone_flags) { if (!asan_inited) __asan_init(); GET_STACK_TRACE_MALLOC; + uptr page_size = GetPageSizeCached(); + uptr allocated_size = RoundUpTo(sizeof(asan_zone), page_size); malloc_zone_t *new_zone = - (malloc_zone_t*)asan_malloc(sizeof(asan_zone), &stack); + (malloc_zone_t*)asan_memalign(page_size, allocated_size, + &stack, FROM_MALLOC); internal_memcpy(new_zone, &asan_zone, sizeof(asan_zone)); new_zone->zone_name = NULL; // The name will be changed anyway. + if (GetMacosVersion() >= MACOS_VERSION_LION) { + // Prevent the client app from overwriting the zone contents. + // Library functions that need to modify the zone will set PROT_WRITE on it. + // This matches the behavior of malloc_create_zone() on OSX 10.7 and higher. + mprotect(new_zone, allocated_size, PROT_READ); + } return new_zone; } diff --git a/lib/asan/asan_malloc_win.cc b/lib/asan/asan_malloc_win.cc index 31fb777c7045..73e4c825092c 100644 --- a/lib/asan/asan_malloc_win.cc +++ b/lib/asan/asan_malloc_win.cc @@ -32,11 +32,13 @@ using namespace __asan; // NOLINT // revisited in the future. extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE void free(void *ptr) { GET_STACK_TRACE_FREE; return asan_free(ptr, &stack, FROM_MALLOC); } +SANITIZER_INTERFACE_ATTRIBUTE void _free_dbg(void* ptr, int) { free(ptr); } @@ -45,38 +47,46 @@ void cfree(void *ptr) { CHECK(!"cfree() should not be used on Windows?"); } +SANITIZER_INTERFACE_ATTRIBUTE void *malloc(size_t size) { GET_STACK_TRACE_MALLOC; return asan_malloc(size, &stack); } +SANITIZER_INTERFACE_ATTRIBUTE void* _malloc_dbg(size_t size, int , const char*, int) { return malloc(size); } +SANITIZER_INTERFACE_ATTRIBUTE void *calloc(size_t nmemb, size_t size) { GET_STACK_TRACE_MALLOC; return asan_calloc(nmemb, size, &stack); } +SANITIZER_INTERFACE_ATTRIBUTE void* _calloc_dbg(size_t n, size_t size, int, const char*, int) { return calloc(n, size); } +SANITIZER_INTERFACE_ATTRIBUTE void *_calloc_impl(size_t nmemb, size_t size, int *errno_tmp) { return calloc(nmemb, size); } +SANITIZER_INTERFACE_ATTRIBUTE void *realloc(void *ptr, size_t size) { GET_STACK_TRACE_MALLOC; return asan_realloc(ptr, size, &stack); } +SANITIZER_INTERFACE_ATTRIBUTE void *_realloc_dbg(void *ptr, size_t size, int) { CHECK(!"_realloc_dbg should not exist!"); return 0; } +SANITIZER_INTERFACE_ATTRIBUTE void* _recalloc(void* p, size_t n, size_t elem_size) { if (!p) return calloc(n, elem_size); @@ -86,9 +96,11 @@ void* _recalloc(void* p, size_t n, size_t elem_size) { return realloc(p, size); } +SANITIZER_INTERFACE_ATTRIBUTE size_t _msize(void *ptr) { - GET_STACK_TRACE_MALLOC; - return asan_malloc_usable_size(ptr, &stack); + GET_CURRENT_PC_BP_SP; + (void)sp; + return asan_malloc_usable_size(ptr, pc, bp); } int _CrtDbgReport(int, const char*, int, diff --git a/lib/asan/asan_mapping.h b/lib/asan/asan_mapping.h index f04629222419..1fecaeb35e1e 100644 --- a/lib/asan/asan_mapping.h +++ b/lib/asan/asan_mapping.h @@ -49,6 +49,20 @@ // || `[0x24000000, 0x27ffffff]` || ShadowGap || // || `[0x20000000, 0x23ffffff]` || LowShadow || // || `[0x00000000, 0x1fffffff]` || LowMem || +// +// Default Linux/MIPS mapping: +// || `[0x2aaa8000, 0xffffffff]` || HighMem || +// || `[0x0fffd000, 0x2aaa7fff]` || HighShadow || +// || `[0x0bffd000, 0x0fffcfff]` || ShadowGap || +// || `[0x0aaa8000, 0x0bffcfff]` || LowShadow || +// || `[0x00000000, 0x0aaa7fff]` || LowMem || + +static const u64 kDefaultShadowScale = 3; +static const u64 kDefaultShadowOffset32 = 1ULL << 29; +static const u64 kDefaultShadowOffset64 = 1ULL << 44; +static const u64 kDefaultShort64bitShadowOffset = 0x7FFF8000; // < 2G. +static const u64 kPPC64_ShadowOffset64 = 1ULL << 41; +static const u64 kMIPS32_ShadowOffset32 = 0x0aaa8000; #if ASAN_FLEXIBLE_MAPPING_AND_OFFSET == 1 extern SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_mapping_scale; @@ -56,22 +70,23 @@ extern SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_mapping_offset; # define SHADOW_SCALE (__asan_mapping_scale) # define SHADOW_OFFSET (__asan_mapping_offset) #else +# define SHADOW_SCALE kDefaultShadowScale # if SANITIZER_ANDROID -# define SHADOW_SCALE (3) # define SHADOW_OFFSET (0) # else -# define SHADOW_SCALE (3) # if SANITIZER_WORDSIZE == 32 -# define SHADOW_OFFSET (1 << 29) +# if defined(__mips__) +# define SHADOW_OFFSET kMIPS32_ShadowOffset32 +# else +# define SHADOW_OFFSET kDefaultShadowOffset32 +# endif # else # if defined(__powerpc64__) -# define SHADOW_OFFSET (1ULL << 41) +# define SHADOW_OFFSET kPPC64_ShadowOffset64 +# elif SANITIZER_MAC +# define SHADOW_OFFSET kDefaultShadowOffset64 # else -# if SANITIZER_MAC -# define SHADOW_OFFSET (1ULL << 44) -# else -# define SHADOW_OFFSET 0x7fff8000ULL -# endif +# define SHADOW_OFFSET kDefaultShort64bitShadowOffset # endif # endif # endif @@ -133,7 +148,6 @@ static uptr kHighMemEnd = 0x7fffffffffffULL; static uptr kMidMemBeg = 0x3000000000ULL; static uptr kMidMemEnd = 0x4fffffffffULL; #else -SANITIZER_INTERFACE_ATTRIBUTE extern uptr kHighMemEnd, kMidMemBeg, kMidMemEnd; // Initialized in __asan_init. #endif diff --git a/lib/asan/asan_poisoning.cc b/lib/asan/asan_poisoning.cc index 772b5e64b027..280aaeb909a3 100644 --- a/lib/asan/asan_poisoning.cc +++ b/lib/asan/asan_poisoning.cc @@ -14,6 +14,7 @@ #include "asan_poisoning.h" #include "sanitizer_common/sanitizer_libc.h" +#include "sanitizer_common/sanitizer_flags.h" namespace __asan { @@ -68,7 +69,7 @@ void __asan_poison_memory_region(void const volatile *addr, uptr size) { if (!flags()->allow_user_poisoning || size == 0) return; uptr beg_addr = (uptr)addr; uptr end_addr = beg_addr + size; - if (flags()->verbosity >= 1) { + if (common_flags()->verbosity >= 1) { Printf("Trying to poison memory region [%p, %p)\n", (void*)beg_addr, (void*)end_addr); } @@ -110,7 +111,7 @@ void __asan_unpoison_memory_region(void const volatile *addr, uptr size) { if (!flags()->allow_user_poisoning || size == 0) return; uptr beg_addr = (uptr)addr; uptr end_addr = beg_addr + size; - if (flags()->verbosity >= 1) { + if (common_flags()->verbosity >= 1) { Printf("Trying to unpoison memory region [%p, %p)\n", (void*)beg_addr, (void*)end_addr); } @@ -183,37 +184,37 @@ uptr __asan_region_is_poisoned(uptr beg, uptr size) { extern "C" SANITIZER_INTERFACE_ATTRIBUTE -u16 __sanitizer_unaligned_load16(const u16 *p) { +u16 __sanitizer_unaligned_load16(const uu16 *p) { CHECK_SMALL_REGION(p, sizeof(*p), false); return *p; } extern "C" SANITIZER_INTERFACE_ATTRIBUTE -u32 __sanitizer_unaligned_load32(const u32 *p) { +u32 __sanitizer_unaligned_load32(const uu32 *p) { CHECK_SMALL_REGION(p, sizeof(*p), false); return *p; } extern "C" SANITIZER_INTERFACE_ATTRIBUTE -u64 __sanitizer_unaligned_load64(const u64 *p) { +u64 __sanitizer_unaligned_load64(const uu64 *p) { CHECK_SMALL_REGION(p, sizeof(*p), false); return *p; } extern "C" SANITIZER_INTERFACE_ATTRIBUTE -void __sanitizer_unaligned_store16(u16 *p, u16 x) { +void __sanitizer_unaligned_store16(uu16 *p, u16 x) { CHECK_SMALL_REGION(p, sizeof(*p), true); *p = x; } extern "C" SANITIZER_INTERFACE_ATTRIBUTE -void __sanitizer_unaligned_store32(u32 *p, u32 x) { +void __sanitizer_unaligned_store32(uu32 *p, u32 x) { CHECK_SMALL_REGION(p, sizeof(*p), true); *p = x; } extern "C" SANITIZER_INTERFACE_ATTRIBUTE -void __sanitizer_unaligned_store64(u64 *p, u64 x) { +void __sanitizer_unaligned_store64(uu64 *p, u64 x) { CHECK_SMALL_REGION(p, sizeof(*p), true); *p = x; } @@ -244,13 +245,55 @@ static void PoisonAlignedStackMemory(uptr addr, uptr size, bool do_poison) { } void __asan_poison_stack_memory(uptr addr, uptr size) { - if (flags()->verbosity > 0) + if (common_flags()->verbosity > 0) Report("poisoning: %p %zx\n", (void*)addr, size); PoisonAlignedStackMemory(addr, size, true); } void __asan_unpoison_stack_memory(uptr addr, uptr size) { - if (flags()->verbosity > 0) + if (common_flags()->verbosity > 0) Report("unpoisoning: %p %zx\n", (void*)addr, size); PoisonAlignedStackMemory(addr, size, false); } + +void __sanitizer_annotate_contiguous_container(void *beg_p, void *end_p, + void *old_mid_p, + void *new_mid_p) { + uptr beg = reinterpret_cast(beg_p); + uptr end= reinterpret_cast(end_p); + uptr old_mid = reinterpret_cast(old_mid_p); + uptr new_mid = reinterpret_cast(new_mid_p); + uptr granularity = SHADOW_GRANULARITY; + CHECK(beg <= end && beg <= old_mid && beg <= new_mid && old_mid <= end && + new_mid <= end && IsAligned(beg, granularity)); + CHECK_LE(end - beg, + FIRST_32_SECOND_64(1UL << 30, 1UL << 34)); // Sanity check. + + uptr a = RoundDownTo(Min(old_mid, new_mid), granularity); + uptr c = RoundUpTo(Max(old_mid, new_mid), granularity); + uptr b = new_mid; + uptr b1 = RoundDownTo(b, granularity); + uptr b2 = RoundUpTo(b, granularity); + uptr d = old_mid; + uptr d1 = RoundDownTo(d, granularity); + uptr d2 = RoundUpTo(d, granularity); + // Currently we should be in this state: + // [a, d1) is good, [d2, c) is bad, [d1, d2) is partially good. + // Make a quick sanity check that we are indeed in this state. + if (d1 != d2) + CHECK_EQ(*(u8*)MemToShadow(d1), d - d1); + if (a + granularity <= d1) + CHECK_EQ(*(u8*)MemToShadow(a), 0); + if (d2 + granularity <= c && c <= end) + CHECK_EQ(*(u8 *)MemToShadow(c - granularity), kAsanUserPoisonedMemoryMagic); + + // New state: + // [a, b1) is good, [b2, c) is bad, [b1, b2) is partially good. + // FIXME: we may want to have a separate poison magic value. + PoisonShadow(a, b1 - a, 0); + PoisonShadow(b2, c - b2, kAsanUserPoisonedMemoryMagic); + if (b1 != b2) { + CHECK_EQ(b2 - b1, granularity); + *(u8*)MemToShadow(b1) = static_cast(b - b1); + } +} diff --git a/lib/asan/asan_poisoning.h b/lib/asan/asan_poisoning.h index 86f81e5d0ae5..fbac21196b8f 100644 --- a/lib/asan/asan_poisoning.h +++ b/lib/asan/asan_poisoning.h @@ -43,6 +43,7 @@ ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size, ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone( uptr aligned_addr, uptr size, uptr redzone_size, u8 value) { DCHECK(flags()->poison_heap); + bool poison_partial = flags()->poison_partial; u8 *shadow = (u8*)MEM_TO_SHADOW(aligned_addr); for (uptr i = 0; i < redzone_size; i += SHADOW_GRANULARITY, shadow++) { if (i + SHADOW_GRANULARITY <= size) { @@ -50,7 +51,8 @@ ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone( } else if (i >= size) { *shadow = (SHADOW_GRANULARITY == 128) ? 0xff : value; // unaddressable } else { - *shadow = size - i; // first size-i bytes are addressable + // first size-i bytes are addressable + *shadow = poison_partial ? static_cast(size - i) : 0; } } } diff --git a/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc index 5126a756d1c8..bcc6b381a785 100644 --- a/lib/asan/asan_posix.cc +++ b/lib/asan/asan_posix.cc @@ -1,4 +1,4 @@ -//===-- asan_linux.cc -----------------------------------------------------===// +//===-- asan_posix.cc -----------------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -44,7 +44,7 @@ static void MaybeInstallSigaction(int signum, sigact.sa_flags = SA_SIGINFO; if (flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK; CHECK_EQ(0, REAL(sigaction)(signum, &sigact, 0)); - if (flags()->verbosity >= 1) { + if (common_flags()->verbosity >= 1) { Report("Installed the sigaction for signal %d\n", signum); } } @@ -71,7 +71,7 @@ void SetAlternateSignalStack() { altstack.ss_flags = 0; altstack.ss_size = kAltStackSize; CHECK_EQ(0, sigaltstack(&altstack, 0)); - if (flags()->verbosity > 0) { + if (common_flags()->verbosity > 0) { Report("Alternative stack for T%d set: [%p,%p)\n", GetCurrentTidOrInvalid(), altstack.ss_sp, (char*)altstack.ss_sp + altstack.ss_size); @@ -116,6 +116,15 @@ void AsanTSDSet(void *tsd) { pthread_setspecific(tsd_key, tsd); } +void PlatformTSDDtor(void *tsd) { + AsanThreadContext *context = (AsanThreadContext*)tsd; + if (context->destructor_iterations > 1) { + context->destructor_iterations--; + CHECK_EQ(0, pthread_setspecific(tsd_key, tsd)); + return; + } + AsanThread::TSDDtor(tsd); +} } // namespace __asan #endif // SANITIZER_LINUX || SANITIZER_MAC diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc index aeeebf452ca8..ed4e433c7a54 100644 --- a/lib/asan/asan_report.cc +++ b/lib/asan/asan_report.cc @@ -20,6 +20,7 @@ #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_report_decorator.h" +#include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_symbolizer.h" namespace __asan { @@ -44,15 +45,6 @@ void AppendToErrorMessageBuffer(const char *buffer) { } // ---------------------- Decorator ------------------------------ {{{1 -bool PrintsToTtyCached() { - static int cached = 0; - static bool prints_to_tty; - if (!cached) { // Ok wrt threads since we are printing only from one thread. - prints_to_tty = PrintsToTty(); - cached = 1; - } - return prints_to_tty; -} class Decorator: private __sanitizer::AnsiColorDecorator { public: Decorator() : __sanitizer::AnsiColorDecorator(PrintsToTtyCached()) { } @@ -113,7 +105,7 @@ static void PrintShadowBytes(const char *before, u8 *bytes, for (uptr i = 0; i < n; i++) { u8 *p = bytes + i; const char *before = p == guilty ? "[" : - p - 1 == guilty ? "" : " "; + (p - 1 == guilty && i != 0) ? "" : " "; const char *after = p == guilty ? "]" : ""; PrintShadowByte(before, *p, after); } @@ -125,7 +117,7 @@ static void PrintLegend() { "application bytes):\n", (int)SHADOW_GRANULARITY); PrintShadowByte(" Addressable: ", 0); Printf(" Partially addressable: "); - for (uptr i = 1; i < SHADOW_GRANULARITY; i++) + for (u8 i = 1; i < SHADOW_GRANULARITY; i++) PrintShadowByte("", i, " "); Printf("\n"); PrintShadowByte(" Heap left redzone: ", kAsanHeapLeftRedzoneMagic); @@ -175,6 +167,11 @@ static void PrintZoneForPointer(uptr ptr, uptr zone_ptr, } } +static void DescribeThread(AsanThread *t) { + if (t) + DescribeThread(t->context()); +} + // ---------------------- Address Descriptions ------------------- {{{1 static bool IsASCII(unsigned char c) { @@ -184,7 +181,9 @@ static bool IsASCII(unsigned char c) { static const char *MaybeDemangleGlobalName(const char *name) { // We can spoil names of globals with C linkage, so use an heuristic // approach to check if the name should be demangled. - return (name[0] == '_' && name[1] == 'Z') ? Demangle(name) : name; + return (name[0] == '_' && name[1] == 'Z') + ? Symbolizer::Get()->Demangle(name) + : name; } // Check if the global is a zero-terminated ASCII string. If so, print it. @@ -264,10 +263,53 @@ const char *ThreadNameWithParenthesis(u32 tid, char buff[], return ThreadNameWithParenthesis(t, buff, buff_len); } +void PrintAccessAndVarIntersection(const char *var_name, + uptr var_beg, uptr var_size, + uptr addr, uptr access_size, + uptr prev_var_end, uptr next_var_beg) { + uptr var_end = var_beg + var_size; + uptr addr_end = addr + access_size; + const char *pos_descr = 0; + // If the variable [var_beg, var_end) is the nearest variable to the + // current memory access, indicate it in the log. + if (addr >= var_beg) { + if (addr_end <= var_end) + pos_descr = "is inside"; // May happen if this is a use-after-return. + else if (addr < var_end) + pos_descr = "partially overflows"; + else if (addr_end <= next_var_beg && + next_var_beg - addr_end >= addr - var_end) + pos_descr = "overflows"; + } else { + if (addr_end > var_beg) + pos_descr = "partially underflows"; + else if (addr >= prev_var_end && + addr - prev_var_end >= var_beg - addr_end) + pos_descr = "underflows"; + } + Printf(" [%zd, %zd) '%s'", var_beg, var_beg + var_size, var_name); + if (pos_descr) { + Decorator d; + // FIXME: we may want to also print the size of the access here, + // but in case of accesses generated by memset it may be confusing. + Printf("%s <== Memory access at offset %zd %s this variable%s\n", + d.Location(), addr, pos_descr, d.EndLocation()); + } else { + Printf("\n"); + } +} + +struct StackVarDescr { + uptr beg; + uptr size; + const char *name_pos; + uptr name_len; +}; + bool DescribeAddressIfStack(uptr addr, uptr access_size) { AsanThread *t = FindThreadByStackAddress(addr); if (!t) return false; - const sptr kBufSize = 4095; + const uptr kBufSize = 4095; char buf[kBufSize]; uptr offset = 0; uptr frame_pc = 0; @@ -306,31 +348,44 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size) { PrintStack(&alloca_stack); // Report the number of stack objects. char *p; - uptr n_objects = internal_simple_strtoll(frame_descr, &p, 10); + uptr n_objects = (uptr)internal_simple_strtoll(frame_descr, &p, 10); CHECK_GT(n_objects, 0); Printf(" This frame has %zu object(s):\n", n_objects); + // Report all objects in this frame. + InternalScopedBuffer vars(n_objects); for (uptr i = 0; i < n_objects; i++) { uptr beg, size; - sptr len; - beg = internal_simple_strtoll(p, &p, 10); - size = internal_simple_strtoll(p, &p, 10); - len = internal_simple_strtoll(p, &p, 10); - if (beg <= 0 || size <= 0 || len < 0 || *p != ' ') { + uptr len; + beg = (uptr)internal_simple_strtoll(p, &p, 10); + size = (uptr)internal_simple_strtoll(p, &p, 10); + len = (uptr)internal_simple_strtoll(p, &p, 10); + if (beg == 0 || size == 0 || *p != ' ') { Printf("AddressSanitizer can't parse the stack frame " "descriptor: |%s|\n", frame_descr); break; } p++; - buf[0] = 0; - internal_strncat(buf, p, Min(kBufSize, len)); + vars[i].beg = beg; + vars[i].size = size; + vars[i].name_pos = p; + vars[i].name_len = len; p += len; - Printf(" [%zu, %zu) '%s'\n", beg, beg + size, buf); + } + for (uptr i = 0; i < n_objects; i++) { + buf[0] = 0; + internal_strncat(buf, vars[i].name_pos, + static_cast(Min(kBufSize, vars[i].name_len))); + uptr prev_var_end = i ? vars[i - 1].beg + vars[i - 1].size : 0; + uptr next_var_beg = i + 1 < n_objects ? vars[i + 1].beg : ~(0UL); + PrintAccessAndVarIntersection(buf, vars[i].beg, vars[i].size, + offset, access_size, + prev_var_end, next_var_beg); } Printf("HINT: this may be a false positive if your program uses " "some custom stack unwind mechanism or swapcontext\n" " (longjmp and C++ exceptions *are* supported)\n"); - DescribeThread(t->context()); + DescribeThread(t); return true; } @@ -360,7 +415,11 @@ static void DescribeAccessToHeapChunk(AsanChunkView chunk, uptr addr, void DescribeHeapAddress(uptr addr, uptr access_size) { AsanChunkView chunk = FindHeapChunkByAddress(addr); - if (!chunk.IsValid()) return; + if (!chunk.IsValid()) { + Printf("AddressSanitizer can not describe address in more detail " + "(wild memory access suspected).\n"); + return; + } DescribeAccessToHeapChunk(chunk, addr, access_size); CHECK(chunk.AllocTid() != kInvalidTid); asanThreadRegistry().CheckLocked(); @@ -368,13 +427,11 @@ void DescribeHeapAddress(uptr addr, uptr access_size) { GetThreadContextByTidLocked(chunk.AllocTid()); StackTrace alloc_stack; chunk.GetAllocStack(&alloc_stack); - AsanThread *t = GetCurrentThread(); - CHECK(t); char tname[128]; Decorator d; + AsanThreadContext *free_thread = 0; if (chunk.FreeTid() != kInvalidTid) { - AsanThreadContext *free_thread = - GetThreadContextByTidLocked(chunk.FreeTid()); + free_thread = GetThreadContextByTidLocked(chunk.FreeTid()); Printf("%sfreed by thread T%d%s here:%s\n", d.Allocation(), free_thread->tid, ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)), @@ -386,19 +443,17 @@ void DescribeHeapAddress(uptr addr, uptr access_size) { d.Allocation(), alloc_thread->tid, ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)), d.EndAllocation()); - PrintStack(&alloc_stack); - DescribeThread(t->context()); - DescribeThread(free_thread); - DescribeThread(alloc_thread); } else { Printf("%sallocated by thread T%d%s here:%s\n", d.Allocation(), alloc_thread->tid, ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)), d.EndAllocation()); - PrintStack(&alloc_stack); - DescribeThread(t->context()); - DescribeThread(alloc_thread); } + PrintStack(&alloc_stack); + DescribeThread(GetCurrentThread()); + if (free_thread) + DescribeThread(free_thread); + DescribeThread(alloc_thread); } void DescribeAddress(uptr addr, uptr access_size) { @@ -431,7 +486,9 @@ void DescribeThread(AsanThreadContext *context) { context->parent_tid, ThreadNameWithParenthesis(context->parent_tid, tname, sizeof(tname))); - PrintStack(&context->stack); + uptr stack_size; + const uptr *stack_trace = StackDepotGet(context->stack_id, &stack_size); + PrintStack(stack_trace, stack_size); // Recursively described parent thread if needed. if (flags()->print_full_thread_history) { AsanThreadContext *parent_context = @@ -476,21 +533,11 @@ class ScopedInErrorReport { reporting_thread_tid = GetCurrentTidOrInvalid(); Printf("====================================================" "=============\n"); - if (reporting_thread_tid != kInvalidTid) { - // We started reporting an error message. Stop using the fake stack - // in case we call an instrumented function from a symbolizer. - AsanThread *curr_thread = GetCurrentThread(); - CHECK(curr_thread); - curr_thread->fake_stack().StopUsingFakeStack(); - } } // Destructor is NORETURN, as functions that report errors are. NORETURN ~ScopedInErrorReport() { // Make sure the current thread is announced. - AsanThread *curr_thread = GetCurrentThread(); - if (curr_thread) { - DescribeThread(curr_thread->context()); - } + DescribeThread(GetCurrentThread()); // Print memory stats. if (flags()->print_stats) __asan_print_accumulated_stats(); @@ -502,22 +549,6 @@ class ScopedInErrorReport { } }; -static void ReportSummary(const char *error_type, StackTrace *stack) { - if (!stack->size) return; - if (IsSymbolizerAvailable()) { - AddressInfo ai; - // Currently, we include the first stack frame into the report summary. - // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc). - uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]); - SymbolizeCode(pc, &ai, 1); - ReportErrorSummary(error_type, - StripPathPrefix(ai.file, - common_flags()->strip_path_prefix), - ai.line, ai.function); - } - // FIXME: do we need to print anything at all if there is no symbolizer? -} - void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) { ScopedInErrorReport in_report; Decorator d; @@ -527,13 +558,13 @@ void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) { (void*)addr, (void*)pc, (void*)sp, (void*)bp, GetCurrentTidOrInvalid()); Printf("%s", d.EndWarning()); - Printf("AddressSanitizer can not provide additional info.\n"); GET_STACK_TRACE_FATAL(pc, bp); PrintStack(&stack); - ReportSummary("SEGV", &stack); + Printf("AddressSanitizer can not provide additional info.\n"); + ReportErrorSummary("SEGV", &stack); } -void ReportDoubleFree(uptr addr, StackTrace *stack) { +void ReportDoubleFree(uptr addr, StackTrace *free_stack) { ScopedInErrorReport in_report; Decorator d; Printf("%s", d.Warning()); @@ -543,14 +574,15 @@ void ReportDoubleFree(uptr addr, StackTrace *stack) { "thread T%d%s:\n", addr, curr_tid, ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname))); - Printf("%s", d.EndWarning()); - PrintStack(stack); + CHECK_GT(free_stack->size, 0); + GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); + PrintStack(&stack); DescribeHeapAddress(addr, 1); - ReportSummary("double-free", stack); + ReportErrorSummary("double-free", &stack); } -void ReportFreeNotMalloced(uptr addr, StackTrace *stack) { +void ReportFreeNotMalloced(uptr addr, StackTrace *free_stack) { ScopedInErrorReport in_report; Decorator d; Printf("%s", d.Warning()); @@ -560,12 +592,14 @@ void ReportFreeNotMalloced(uptr addr, StackTrace *stack) { "which was not malloc()-ed: %p in thread T%d%s\n", addr, curr_tid, ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname))); Printf("%s", d.EndWarning()); - PrintStack(stack); + CHECK_GT(free_stack->size, 0); + GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); + PrintStack(&stack); DescribeHeapAddress(addr, 1); - ReportSummary("bad-free", stack); + ReportErrorSummary("bad-free", &stack); } -void ReportAllocTypeMismatch(uptr addr, StackTrace *stack, +void ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack, AllocType alloc_type, AllocType dealloc_type) { static const char *alloc_names[] = @@ -579,9 +613,11 @@ void ReportAllocTypeMismatch(uptr addr, StackTrace *stack, Report("ERROR: AddressSanitizer: alloc-dealloc-mismatch (%s vs %s) on %p\n", alloc_names[alloc_type], dealloc_names[dealloc_type], addr); Printf("%s", d.EndWarning()); - PrintStack(stack); + CHECK_GT(free_stack->size, 0); + GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp); + PrintStack(&stack); DescribeHeapAddress(addr, 1); - ReportSummary("alloc-dealloc-mismatch", stack); + ReportErrorSummary("alloc-dealloc-mismatch", &stack); Report("HINT: if you don't care about these warnings you may set " "ASAN_OPTIONS=alloc_dealloc_mismatch=0\n"); } @@ -596,7 +632,7 @@ void ReportMallocUsableSizeNotOwned(uptr addr, StackTrace *stack) { Printf("%s", d.EndWarning()); PrintStack(stack); DescribeHeapAddress(addr, 1); - ReportSummary("bad-malloc_usable_size", stack); + ReportErrorSummary("bad-malloc_usable_size", stack); } void ReportAsanGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) { @@ -609,7 +645,7 @@ void ReportAsanGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) { Printf("%s", d.EndWarning()); PrintStack(stack); DescribeHeapAddress(addr, 1); - ReportSummary("bad-__asan_get_allocated_size", stack); + ReportErrorSummary("bad-__asan_get_allocated_size", stack); } void ReportStringFunctionMemoryRangesOverlap( @@ -627,7 +663,7 @@ void ReportStringFunctionMemoryRangesOverlap( PrintStack(stack); DescribeAddress((uptr)offset1, length1); DescribeAddress((uptr)offset2, length2); - ReportSummary(bug_type, stack); + ReportErrorSummary(bug_type, stack); } // ----------------------- Mac-specific reports ----------------- {{{1 @@ -737,7 +773,7 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp, PrintStack(&stack); DescribeAddress(addr, access_size); - ReportSummary(bug_descr, &stack); + ReportErrorSummary(bug_descr, &stack); PrintShadowMemoryForAddress(addr); } @@ -758,6 +794,6 @@ void __asan_describe_address(uptr addr) { #if !SANITIZER_SUPPORTS_WEAK_HOOKS // Provide default implementation of __asan_on_error that does nothing // and may be overriden by user. -SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE NOINLINE +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE void __asan_on_error() {} #endif diff --git a/lib/asan/asan_report.h b/lib/asan/asan_report.h index db271fc10e97..f55b57bd4d9f 100644 --- a/lib/asan/asan_report.h +++ b/lib/asan/asan_report.h @@ -33,9 +33,9 @@ void DescribeThread(AsanThreadContext *context); // Different kinds of error reports. void NORETURN ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr); -void NORETURN ReportDoubleFree(uptr addr, StackTrace *stack); -void NORETURN ReportFreeNotMalloced(uptr addr, StackTrace *stack); -void NORETURN ReportAllocTypeMismatch(uptr addr, StackTrace *stack, +void NORETURN ReportDoubleFree(uptr addr, StackTrace *free_stack); +void NORETURN ReportFreeNotMalloced(uptr addr, StackTrace *free_stack); +void NORETURN ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack, AllocType alloc_type, AllocType dealloc_type); void NORETURN ReportMallocUsableSizeNotOwned(uptr addr, diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc index f989c5c0d2a5..11f05954d31e 100644 --- a/lib/asan/asan_rtl.cc +++ b/lib/asan/asan_rtl.cc @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "asan_allocator.h" #include "asan_interceptors.h" +#include "asan_interface_internal.h" #include "asan_internal.h" #include "asan_mapping.h" #include "asan_poisoning.h" @@ -26,6 +27,8 @@ #include "sanitizer_common/sanitizer_symbolizer.h" #include "lsan/lsan_common.h" +int __asan_option_detect_stack_use_after_return; // Global interface symbol. + namespace __asan { uptr AsanMappingProfile[kAsanMappingProfileSize]; @@ -89,7 +92,6 @@ static void ParseFlagsFromString(Flags *f, const char *str) { CHECK((uptr)common_flags()->malloc_context_size <= kStackTraceMax); ParseFlag(str, &f->quarantine_size, "quarantine_size"); - ParseFlag(str, &f->verbosity, "verbosity"); ParseFlag(str, &f->redzone, "redzone"); CHECK_GE(f->redzone, 16); CHECK(IsPowerOfTwo(f->redzone)); @@ -101,7 +103,9 @@ static void ParseFlagsFromString(Flags *f, const char *str) { ParseFlag(str, &f->replace_str, "replace_str"); ParseFlag(str, &f->replace_intrin, "replace_intrin"); ParseFlag(str, &f->mac_ignore_invalid_free, "mac_ignore_invalid_free"); - ParseFlag(str, &f->use_fake_stack, "use_fake_stack"); + ParseFlag(str, &f->detect_stack_use_after_return, + "detect_stack_use_after_return"); + ParseFlag(str, &f->uar_stack_size_log, "uar_stack_size_log"); ParseFlag(str, &f->max_malloc_fill_size, "max_malloc_fill_size"); ParseFlag(str, &f->malloc_fill_byte, "malloc_fill_byte"); ParseFlag(str, &f->exitcode, "exitcode"); @@ -116,30 +120,25 @@ static void ParseFlagsFromString(Flags *f, const char *str) { ParseFlag(str, &f->print_stats, "print_stats"); ParseFlag(str, &f->print_legend, "print_legend"); ParseFlag(str, &f->atexit, "atexit"); + ParseFlag(str, &f->coverage, "coverage"); ParseFlag(str, &f->disable_core, "disable_core"); ParseFlag(str, &f->allow_reexec, "allow_reexec"); ParseFlag(str, &f->print_full_thread_history, "print_full_thread_history"); - ParseFlag(str, &f->log_path, "log_path"); ParseFlag(str, &f->poison_heap, "poison_heap"); + ParseFlag(str, &f->poison_partial, "poison_partial"); ParseFlag(str, &f->alloc_dealloc_mismatch, "alloc_dealloc_mismatch"); - ParseFlag(str, &f->use_stack_depot, "use_stack_depot"); ParseFlag(str, &f->strict_memcmp, "strict_memcmp"); ParseFlag(str, &f->strict_init_order, "strict_init_order"); - ParseFlag(str, &f->detect_leaks, "detect_leaks"); } void InitializeFlags(Flags *f, const char *env) { CommonFlags *cf = common_flags(); + SetCommonFlagDefaults(); cf->external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH"); - cf->symbolize = true; cf->malloc_context_size = kDefaultMallocContextSize; - cf->fast_unwind_on_fatal = false; - cf->fast_unwind_on_malloc = true; - cf->strip_path_prefix = ""; internal_memset(f, 0, sizeof(*f)); f->quarantine_size = (ASAN_LOW_MEMORY) ? 1UL << 26 : 1UL << 28; - f->verbosity = 0; f->redzone = 16; f->debug = false; f->report_globals = 1; @@ -147,7 +146,8 @@ void InitializeFlags(Flags *f, const char *env) { f->replace_str = true; f->replace_intrin = true; f->mac_ignore_invalid_free = false; - f->use_fake_stack = true; + f->detect_stack_use_after_return = false; // Also needs the compiler flag. + f->uar_stack_size_log = 0; f->max_malloc_fill_size = 0x1000; // By default, fill only the first 4K. f->malloc_fill_byte = 0xbe; f->exitcode = ASAN_DEFAULT_FAILURE_EXITCODE; @@ -162,25 +162,24 @@ void InitializeFlags(Flags *f, const char *env) { f->print_stats = false; f->print_legend = true; f->atexit = false; + f->coverage = false; f->disable_core = (SANITIZER_WORDSIZE == 64); f->allow_reexec = true; f->print_full_thread_history = true; - f->log_path = 0; f->poison_heap = true; - // Turn off alloc/dealloc mismatch checker on Mac for now. - // TODO(glider): Fix known issues and enable this back. - f->alloc_dealloc_mismatch = (SANITIZER_MAC == 0);; - f->use_stack_depot = true; + f->poison_partial = true; + // Turn off alloc/dealloc mismatch checker on Mac and Windows for now. + // TODO(glider,timurrrr): Fix known issues and enable this back. + f->alloc_dealloc_mismatch = (SANITIZER_MAC == 0) && (SANITIZER_WINDOWS == 0); f->strict_memcmp = true; f->strict_init_order = false; - f->detect_leaks = false; // Override from compile definition. ParseFlagsFromString(f, MaybeUseAsanDefaultOptionsCompileDefiniton()); // Override from user-specified string. ParseFlagsFromString(f, MaybeCallAsanDefaultOptions()); - if (flags()->verbosity) { + if (common_flags()->verbosity) { Report("Using the defaults from __asan_default_options: %s\n", MaybeCallAsanDefaultOptions()); } @@ -189,17 +188,17 @@ void InitializeFlags(Flags *f, const char *env) { ParseFlagsFromString(f, env); #if !CAN_SANITIZE_LEAKS - if (f->detect_leaks) { + if (cf->detect_leaks) { Report("%s: detect_leaks is not supported on this platform.\n", SanitizerToolName); - f->detect_leaks = false; + cf->detect_leaks = false; } #endif - if (f->detect_leaks && !f->use_stack_depot) { - Report("%s: detect_leaks is ignored (requires use_stack_depot).\n", - SanitizerToolName); - f->detect_leaks = false; + // Make "strict_init_order" imply "check_initialization_order". + // TODO(samsonov): Use a single runtime flag for an init-order checker. + if (f->strict_init_order) { + f->check_initialization_order = true; } } @@ -305,8 +304,6 @@ static NOINLINE void force_interface_symbols() { case 25: __asan_poison_memory_region(0, 0); break; case 26: __asan_unpoison_memory_region(0, 0); break; case 27: __asan_set_error_exit_code(0); break; - case 28: __asan_stack_free(0, 0, 0); break; - case 29: __asan_stack_malloc(0, 0); break; case 30: __asan_before_dynamic_init(0); break; case 31: __asan_after_dynamic_init(); break; case 32: __asan_poison_stack_memory(0, 0); break; @@ -328,22 +325,12 @@ static void asan_atexit() { static void InitializeHighMemEnd() { #if !ASAN_FIXED_MAPPING -#if SANITIZER_WORDSIZE == 64 -# if defined(__powerpc64__) - // FIXME: - // On PowerPC64 we have two different address space layouts: 44- and 46-bit. - // We somehow need to figure our which one we are using now and choose - // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL. - // Note that with 'ulimit -s unlimited' the stack is moved away from the top - // of the address space, so simply checking the stack address is not enough. - kHighMemEnd = (1ULL << 44) - 1; // 0x00000fffffffffffUL -# else - kHighMemEnd = (1ULL << 47) - 1; // 0x00007fffffffffffUL; -# endif -#else // SANITIZER_WORDSIZE == 32 - kHighMemEnd = (1ULL << 32) - 1; // 0xffffffff; -#endif // SANITIZER_WORDSIZE + kHighMemEnd = GetMaxVirtualAddress(); + // Increase kHighMemEnd to make sure it's properly + // aligned together with kHighMemBeg: + kHighMemEnd |= SHADOW_GRANULARITY * GetPageSizeCached() - 1; #endif // !ASAN_FIXED_MAPPING + CHECK_EQ((kHighMemBeg % GetPageSizeCached()), 0); } static void ProtectGap(uptr a, uptr size) { @@ -385,6 +372,7 @@ static void PrintAddressSpaceLayout() { } Printf("\n"); Printf("red_zone=%zu\n", (uptr)flags()->redzone); + Printf("quarantine_size=%zuM\n", (uptr)flags()->quarantine_size >> 20); Printf("malloc_context_size=%zu\n", (uptr)common_flags()->malloc_context_size); @@ -405,7 +393,7 @@ using namespace __asan; // NOLINT #if !SANITIZER_SUPPORTS_WEAK_HOOKS extern "C" { -SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE const char* __asan_default_options() { return ""; } } // extern "C" #endif @@ -438,6 +426,8 @@ void NOINLINE __asan_handle_no_return() { return; } PoisonShadow(bottom, top - bottom, 0); + if (curr_thread->has_fake_stack()) + curr_thread->fake_stack()->HandleNoReturn(); } void NOINLINE __asan_set_death_callback(void (*callback)(void)) { @@ -463,9 +453,11 @@ void __asan_init() { // initialization steps look at flags(). const char *options = GetEnv("ASAN_OPTIONS"); InitializeFlags(flags(), options); - __sanitizer_set_report_path(flags()->log_path); + __sanitizer_set_report_path(common_flags()->log_path); + __asan_option_detect_stack_use_after_return = + flags()->detect_stack_use_after_return; - if (flags()->verbosity && options) { + if (common_flags()->verbosity && options) { Report("Parsed ASAN_OPTIONS: %s\n", options); } @@ -475,21 +467,16 @@ void __asan_init() { // Setup internal allocator callback. SetLowLevelAllocateCallback(OnLowLevelAllocate); - if (flags()->atexit) { - Atexit(asan_atexit); - } - - // interceptors InitializeAsanInterceptors(); ReplaceSystemMalloc(); ReplaceOperatorsNewAndDelete(); uptr shadow_start = kLowShadowBeg; - if (kLowShadowBeg) shadow_start -= GetMmapGranularity(); - uptr shadow_end = kHighShadowEnd; + if (kLowShadowBeg) + shadow_start -= GetMmapGranularity(); bool full_shadow_is_available = - MemoryRangeIsAvailable(shadow_start, shadow_end); + MemoryRangeIsAvailable(shadow_start, kHighShadowEnd); #if SANITIZER_LINUX && defined(__x86_64__) && !ASAN_FIXED_MAPPING if (!full_shadow_is_available) { @@ -498,7 +485,7 @@ void __asan_init() { } #endif - if (flags()->verbosity) + if (common_flags()->verbosity) PrintAddressSpaceLayout(); if (flags()->disable_core) { @@ -515,7 +502,7 @@ void __asan_init() { ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1); } else if (kMidMemBeg && MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) && - MemoryRangeIsAvailable(kMidMemEnd + 1, shadow_end)) { + MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) { CHECK(kLowShadowBeg != kLowShadowEnd); // mmap the low shadow plus at least one page at the left. ReserveShadowMemoryRange(shadow_start, kLowShadowEnd); @@ -534,12 +521,18 @@ void __asan_init() { Die(); } + AsanTSDInit(PlatformTSDDtor); InstallSignalHandlers(); + + // Allocator should be initialized before starting external symbolizer, as + // fork() on Mac locks the allocator. + InitializeAllocator(); + // Start symbolizer process if necessary. - const char* external_symbolizer = common_flags()->external_symbolizer_path; - if (common_flags()->symbolize && external_symbolizer && - external_symbolizer[0]) { - InitializeExternalSymbolizer(external_symbolizer); + if (common_flags()->symbolize) { + Symbolizer::Init(common_flags()->external_symbolizer_path); + } else { + Symbolizer::Disable(); } // On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited @@ -547,8 +540,16 @@ void __asan_init() { asan_inited = 1; asan_init_is_running = false; + if (flags()->atexit) + Atexit(asan_atexit); + + if (flags()->coverage) + Atexit(__sanitizer_cov_dump); + + // interceptors + InitTlsSize(); + // Create main thread. - AsanTSDInit(AsanThread::TSDDtor); AsanThread *main_thread = AsanThread::Create(0, 0); CreateThreadContextArgs create_main_args = { main_thread, 0 }; u32 main_tid = asanThreadRegistry().CreateThread( @@ -558,16 +559,14 @@ void __asan_init() { main_thread->ThreadStart(internal_getpid()); force_interface_symbols(); // no-op. - InitializeAllocator(); - #if CAN_SANITIZE_LEAKS __lsan::InitCommonLsan(); - if (flags()->detect_leaks) { + if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) { Atexit(__lsan::DoLeakCheck); } #endif // CAN_SANITIZE_LEAKS - if (flags()->verbosity) { + if (common_flags()->verbosity) { Report("AddressSanitizer Init done\n"); } } diff --git a/lib/asan/asan_stack.cc b/lib/asan/asan_stack.cc index 21dae7df096a..0bc5a5f2d036 100644 --- a/lib/asan/asan_stack.cc +++ b/lib/asan/asan_stack.cc @@ -24,9 +24,12 @@ static bool MaybeCallAsanSymbolize(const void *pc, char *out_buffer, : false; } +void PrintStack(const uptr *trace, uptr size) { + StackTrace::PrintStack(trace, size, MaybeCallAsanSymbolize); +} + void PrintStack(StackTrace *stack) { - stack->PrintStack(stack->trace, stack->size, common_flags()->symbolize, - common_flags()->strip_path_prefix, MaybeCallAsanSymbolize); + PrintStack(stack->trace, stack->size); } } // namespace __asan @@ -37,7 +40,7 @@ void PrintStack(StackTrace *stack) { // and may be overriden by user if he wants to use his own symbolization. // ASan on Windows has its own implementation of this. #if !SANITIZER_WINDOWS && !SANITIZER_SUPPORTS_WEAK_HOOKS -SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE NOINLINE +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE bool __asan_symbolize(const void *pc, char *out_buffer, int out_size) { return false; } diff --git a/lib/asan/asan_stack.h b/lib/asan/asan_stack.h index 176aa183c93b..7f5fd661eec8 100644 --- a/lib/asan/asan_stack.h +++ b/lib/asan/asan_stack.h @@ -22,6 +22,7 @@ namespace __asan { void PrintStack(StackTrace *stack); +void PrintStack(const uptr *trace, uptr size); } // namespace __asan @@ -29,21 +30,21 @@ void PrintStack(StackTrace *stack); // The pc will be in the position 0 of the resulting stack trace. // The bp may refer to the current frame or to the caller's frame. #if SANITIZER_WINDOWS -#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \ - StackTrace stack; \ - GetStackTrace(&stack, max_s, pc, bp, 0, 0, fast) +#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \ + StackTrace stack; \ + stack.Unwind(max_s, pc, bp, 0, 0, fast) #else -#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \ - StackTrace stack; \ - { \ - uptr stack_top = 0, stack_bottom = 0; \ - AsanThread *t; \ - if (asan_inited && (t = GetCurrentThread())) { \ - stack_top = t->stack_top(); \ - stack_bottom = t->stack_bottom(); \ - } \ - GetStackTrace(&stack, max_s, pc, bp, \ - stack_top, stack_bottom, fast); \ +#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \ + StackTrace stack; \ + { \ + AsanThread *t; \ + stack.size = 0; \ + if (asan_inited && (t = GetCurrentThread()) && !t->isUnwinding()) { \ + uptr stack_top = t->stack_top(); \ + uptr stack_bottom = t->stack_bottom(); \ + ScopedUnwinding unwind_scope(t); \ + stack.Unwind(max_s, pc, bp, stack_top, stack_bottom, fast); \ + } \ } #endif // SANITIZER_WINDOWS diff --git a/lib/asan/asan_stats.cc b/lib/asan/asan_stats.cc index ba7c1ab6e91a..73dc3c5ac44f 100644 --- a/lib/asan/asan_stats.cc +++ b/lib/asan/asan_stats.cc @@ -21,6 +21,10 @@ namespace __asan { AsanStats::AsanStats() { + Clear(); +} + +void AsanStats::Clear() { CHECK(REAL(memset)); REAL(memset)(this, 0, sizeof(AsanStats)); } @@ -54,77 +58,63 @@ void AsanStats::Print() { malloc_large, malloc_small_slow); } -static BlockingMutex print_lock(LINKER_INITIALIZED); - -static void PrintAccumulatedStats() { - AsanStats stats; - GetAccumulatedStats(&stats); - // Use lock to keep reports from mixing up. - BlockingMutexLock lock(&print_lock); - stats.Print(); - StackDepotStats *stack_depot_stats = StackDepotGetStats(); - Printf("Stats: StackDepot: %zd ids; %zdM mapped\n", - stack_depot_stats->n_uniq_ids, stack_depot_stats->mapped >> 20); - PrintInternalAllocatorStats(); +void AsanStats::MergeFrom(const AsanStats *stats) { + uptr *dst_ptr = reinterpret_cast(this); + const uptr *src_ptr = reinterpret_cast(stats); + uptr num_fields = sizeof(*this) / sizeof(uptr); + for (uptr i = 0; i < num_fields; i++) + dst_ptr[i] += src_ptr[i]; } +static BlockingMutex print_lock(LINKER_INITIALIZED); + static AsanStats unknown_thread_stats(LINKER_INITIALIZED); -static AsanStats accumulated_stats(LINKER_INITIALIZED); +static AsanStats dead_threads_stats(LINKER_INITIALIZED); +static BlockingMutex dead_threads_stats_lock(LINKER_INITIALIZED); // Required for malloc_zone_statistics() on OS X. This can't be stored in // per-thread AsanStats. static uptr max_malloced_memory; -static BlockingMutex acc_stats_lock(LINKER_INITIALIZED); - -static void FlushToAccumulatedStatsUnlocked(AsanStats *stats) { - acc_stats_lock.CheckLocked(); - uptr *dst = (uptr*)&accumulated_stats; - uptr *src = (uptr*)stats; - uptr num_fields = sizeof(*stats) / sizeof(uptr); - for (uptr i = 0; i < num_fields; i++) { - dst[i] += src[i]; - src[i] = 0; - } -} -static void FlushThreadStats(ThreadContextBase *tctx_base, void *arg) { +static void MergeThreadStats(ThreadContextBase *tctx_base, void *arg) { + AsanStats *accumulated_stats = reinterpret_cast(arg); AsanThreadContext *tctx = static_cast(tctx_base); if (AsanThread *t = tctx->thread) - FlushToAccumulatedStatsUnlocked(&t->stats()); + accumulated_stats->MergeFrom(&t->stats()); } -static void UpdateAccumulatedStatsUnlocked() { - acc_stats_lock.CheckLocked(); +static void GetAccumulatedStats(AsanStats *stats) { + stats->Clear(); { ThreadRegistryLock l(&asanThreadRegistry()); - asanThreadRegistry().RunCallbackForEachThreadLocked(FlushThreadStats, 0); + asanThreadRegistry() + .RunCallbackForEachThreadLocked(MergeThreadStats, stats); + } + stats->MergeFrom(&unknown_thread_stats); + { + BlockingMutexLock lock(&dead_threads_stats_lock); + stats->MergeFrom(&dead_threads_stats); } - FlushToAccumulatedStatsUnlocked(&unknown_thread_stats); // This is not very accurate: we may miss allocation peaks that happen // between two updates of accumulated_stats_. For more accurate bookkeeping // the maximum should be updated on every malloc(), which is unacceptable. - if (max_malloced_memory < accumulated_stats.malloced) { - max_malloced_memory = accumulated_stats.malloced; + if (max_malloced_memory < stats->malloced) { + max_malloced_memory = stats->malloced; } } -void FlushToAccumulatedStats(AsanStats *stats) { - BlockingMutexLock lock(&acc_stats_lock); - FlushToAccumulatedStatsUnlocked(stats); -} - -void GetAccumulatedStats(AsanStats *stats) { - BlockingMutexLock lock(&acc_stats_lock); - UpdateAccumulatedStatsUnlocked(); - internal_memcpy(stats, &accumulated_stats, sizeof(accumulated_stats)); +void FlushToDeadThreadStats(AsanStats *stats) { + BlockingMutexLock lock(&dead_threads_stats_lock); + dead_threads_stats.MergeFrom(stats); + stats->Clear(); } void FillMallocStatistics(AsanMallocStats *malloc_stats) { - BlockingMutexLock lock(&acc_stats_lock); - UpdateAccumulatedStatsUnlocked(); - malloc_stats->blocks_in_use = accumulated_stats.mallocs; - malloc_stats->size_in_use = accumulated_stats.malloced; + AsanStats stats; + GetAccumulatedStats(&stats); + malloc_stats->blocks_in_use = stats.mallocs; + malloc_stats->size_in_use = stats.malloced; malloc_stats->max_size_in_use = max_malloced_memory; - malloc_stats->size_allocated = accumulated_stats.mmaped; + malloc_stats->size_allocated = stats.mmaped; } AsanStats &GetCurrentThreadStats() { @@ -132,36 +122,48 @@ AsanStats &GetCurrentThreadStats() { return (t) ? t->stats() : unknown_thread_stats; } +static void PrintAccumulatedStats() { + AsanStats stats; + GetAccumulatedStats(&stats); + // Use lock to keep reports from mixing up. + BlockingMutexLock lock(&print_lock); + stats.Print(); + StackDepotStats *stack_depot_stats = StackDepotGetStats(); + Printf("Stats: StackDepot: %zd ids; %zdM mapped\n", + stack_depot_stats->n_uniq_ids, stack_depot_stats->mapped >> 20); + PrintInternalAllocatorStats(); +} + } // namespace __asan // ---------------------- Interface ---------------- {{{1 using namespace __asan; // NOLINT uptr __asan_get_current_allocated_bytes() { - BlockingMutexLock lock(&acc_stats_lock); - UpdateAccumulatedStatsUnlocked(); - uptr malloced = accumulated_stats.malloced; - uptr freed = accumulated_stats.freed; + AsanStats stats; + GetAccumulatedStats(&stats); + uptr malloced = stats.malloced; + uptr freed = stats.freed; // Return sane value if malloced < freed due to racy // way we update accumulated stats. return (malloced > freed) ? malloced - freed : 1; } uptr __asan_get_heap_size() { - BlockingMutexLock lock(&acc_stats_lock); - UpdateAccumulatedStatsUnlocked(); - return accumulated_stats.mmaped - accumulated_stats.munmaped; + AsanStats stats; + GetAccumulatedStats(&stats); + return stats.mmaped - stats.munmaped; } uptr __asan_get_free_bytes() { - BlockingMutexLock lock(&acc_stats_lock); - UpdateAccumulatedStatsUnlocked(); - uptr total_free = accumulated_stats.mmaped - - accumulated_stats.munmaped - + accumulated_stats.really_freed - + accumulated_stats.really_freed_redzones; - uptr total_used = accumulated_stats.malloced - + accumulated_stats.malloced_redzones; + AsanStats stats; + GetAccumulatedStats(&stats); + uptr total_free = stats.mmaped + - stats.munmaped + + stats.really_freed + + stats.really_freed_redzones; + uptr total_used = stats.malloced + + stats.malloced_redzones; // Return sane value if total_free < total_used due to racy // way we update accumulated stats. return (total_free > total_used) ? total_free - total_used : 1; diff --git a/lib/asan/asan_stats.h b/lib/asan/asan_stats.h index 68495fb33f95..e3030e88fdc2 100644 --- a/lib/asan/asan_stats.h +++ b/lib/asan/asan_stats.h @@ -52,18 +52,16 @@ struct AsanStats { // Default ctor for thread-local stats. AsanStats(); - // Prints formatted stats to stderr. - void Print(); + void Print(); // Prints formatted stats to stderr. + void Clear(); + void MergeFrom(const AsanStats *stats); }; // Returns stats for GetCurrentThread(), or stats for fake "unknown thread" // if GetCurrentThread() returns 0. AsanStats &GetCurrentThreadStats(); -// Flushes all thread-local stats to accumulated stats, and makes -// a copy of accumulated stats. -void GetAccumulatedStats(AsanStats *stats); -// Flushes a given stats into accumulated stats. -void FlushToAccumulatedStats(AsanStats *stats); +// Flushes a given stats into accumulated stats of dead threads. +void FlushToDeadThreadStats(AsanStats *stats); // A cross-platform equivalent of malloc_statistics_t on Mac OS. struct AsanMallocStats { diff --git a/lib/asan/asan_thread.cc b/lib/asan/asan_thread.cc index da28381031a5..328ac2fcd398 100644 --- a/lib/asan/asan_thread.cc +++ b/lib/asan/asan_thread.cc @@ -19,6 +19,7 @@ #include "asan_mapping.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_placement_new.h" +#include "sanitizer_common/sanitizer_stackdepot.h" #include "lsan/lsan_common.h" namespace __asan { @@ -27,9 +28,8 @@ namespace __asan { void AsanThreadContext::OnCreated(void *arg) { CreateThreadContextArgs *args = static_cast(arg); - if (args->stack) { - internal_memcpy(&stack, args->stack, sizeof(stack)); - } + if (args->stack) + stack_id = StackDepotPut(args->stack->trace, args->stack->size); thread = args->thread; thread->set_context(this); } @@ -39,12 +39,16 @@ void AsanThreadContext::OnFinished() { thread = 0; } -static char thread_registry_placeholder[sizeof(ThreadRegistry)]; +// MIPS requires aligned address +static ALIGNED(16) char thread_registry_placeholder[sizeof(ThreadRegistry)]; static ThreadRegistry *asan_thread_registry; +static BlockingMutex mu_for_thread_context(LINKER_INITIALIZED); +static LowLevelAllocator allocator_for_thread_context; + static ThreadContextBase *GetAsanThreadContext(u32 tid) { - void *mem = MmapOrDie(sizeof(AsanThreadContext), "AsanThreadContext"); - return new(mem) AsanThreadContext(tid); + BlockingMutexLock lock(&mu_for_thread_context); + return new(allocator_for_thread_context) AsanThreadContext(tid); } ThreadRegistry &asanThreadRegistry() { @@ -84,40 +88,68 @@ AsanThread *AsanThread::Create(thread_callback_t start_routine, void AsanThread::TSDDtor(void *tsd) { AsanThreadContext *context = (AsanThreadContext*)tsd; - if (flags()->verbosity >= 1) + if (common_flags()->verbosity >= 1) Report("T%d TSDDtor\n", context->tid); if (context->thread) context->thread->Destroy(); } void AsanThread::Destroy() { - if (flags()->verbosity >= 1) { + if (common_flags()->verbosity >= 1) { Report("T%d exited\n", tid()); } + malloc_storage().CommitBack(); + if (flags()->use_sigaltstack) UnsetAlternateSignalStack(); asanThreadRegistry().FinishThread(tid()); - FlushToAccumulatedStats(&stats_); + FlushToDeadThreadStats(&stats_); // We also clear the shadow on thread destruction because // some code may still be executing in later TSD destructors // and we don't want it to have any poisoned stack. - ClearShadowForThreadStack(); - fake_stack().Cleanup(); + ClearShadowForThreadStackAndTLS(); + DeleteFakeStack(); uptr size = RoundUpTo(sizeof(AsanThread), GetPageSizeCached()); UnmapOrDie(this, size); } +// We want to create the FakeStack lazyly on the first use, but not eralier +// than the stack size is known and the procedure has to be async-signal safe. +FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() { + uptr stack_size = this->stack_size(); + if (stack_size == 0) // stack_size is not yet available, don't use FakeStack. + return 0; + uptr old_val = 0; + // fake_stack_ has 3 states: + // 0 -- not initialized + // 1 -- being initialized + // ptr -- initialized + // This CAS checks if the state was 0 and if so changes it to state 1, + // if that was successfull, it initilizes the pointer. + if (atomic_compare_exchange_strong( + reinterpret_cast(&fake_stack_), &old_val, 1UL, + memory_order_relaxed)) { + uptr stack_size_log = Log2(RoundUpToPowerOfTwo(stack_size)); + if (flags()->uar_stack_size_log) + stack_size_log = static_cast(flags()->uar_stack_size_log); + fake_stack_ = FakeStack::Create(stack_size_log); + SetTLSFakeStack(fake_stack_); + return fake_stack_; + } + return 0; +} + void AsanThread::Init() { - SetThreadStackTopAndBottom(); + SetThreadStackAndTls(); CHECK(AddrIsInMem(stack_bottom_)); CHECK(AddrIsInMem(stack_top_ - 1)); - ClearShadowForThreadStack(); - if (flags()->verbosity >= 1) { + ClearShadowForThreadStackAndTLS(); + if (common_flags()->verbosity >= 1) { int local = 0; Report("T%d: stack [%p,%p) size 0x%zx; local=%p\n", tid(), (void*)stack_bottom_, (void*)stack_top_, stack_top_ - stack_bottom_, &local); } - fake_stack_.Init(stack_size()); + fake_stack_ = 0; // Will be initialized lazily if needed. AsanPlatformThreadInit(); } @@ -135,22 +167,33 @@ thread_return_t AsanThread::ThreadStart(uptr os_id) { } thread_return_t res = start_routine_(arg_); - malloc_storage().CommitBack(); - if (flags()->use_sigaltstack) UnsetAlternateSignalStack(); - this->Destroy(); + // On POSIX systems we defer this to the TSD destructor. LSan will consider + // the thread's memory as non-live from the moment we call Destroy(), even + // though that memory might contain pointers to heap objects which will be + // cleaned up by a user-defined TSD destructor. Thus, calling Destroy() before + // the TSD destructors have run might cause false positives in LSan. + if (!SANITIZER_POSIX) + this->Destroy(); return res; } -void AsanThread::SetThreadStackTopAndBottom() { - GetThreadStackTopAndBottom(tid() == 0, &stack_top_, &stack_bottom_); +void AsanThread::SetThreadStackAndTls() { + uptr tls_size = 0; + GetThreadStackAndTls(tid() == 0, &stack_bottom_, &stack_size_, &tls_begin_, + &tls_size); + stack_top_ = stack_bottom_ + stack_size_; + tls_end_ = tls_begin_ + tls_size; + int local; CHECK(AddrIsInStack((uptr)&local)); } -void AsanThread::ClearShadowForThreadStack() { +void AsanThread::ClearShadowForThreadStackAndTLS() { PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0); + if (tls_begin_ != tls_end_) + PoisonShadow(tls_begin_, tls_end_ - tls_begin_, 0); } const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset, @@ -158,8 +201,8 @@ const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset, uptr bottom = 0; if (AddrIsInStack(addr)) { bottom = stack_bottom(); - } else { - bottom = fake_stack().AddrIsInFakeStack(addr); + } else if (has_fake_stack()) { + bottom = fake_stack()->AddrIsInFakeStack(addr); CHECK(bottom); *offset = addr - bottom; *frame_pc = ((uptr*)bottom)[2]; @@ -195,13 +238,16 @@ static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base, void *addr) { AsanThreadContext *tctx = static_cast(tctx_base); AsanThread *t = tctx->thread; - return (t && t->fake_stack().StackSize() && - (t->fake_stack().AddrIsInFakeStack((uptr)addr) || - t->AddrIsInStack((uptr)addr))); + if (!t) return false; + if (t->AddrIsInStack((uptr)addr)) return true; + if (t->has_fake_stack() && t->fake_stack()->AddrIsInFakeStack((uptr)addr)) + return true; + return false; } AsanThread *GetCurrentThread() { - AsanThreadContext *context = (AsanThreadContext*)AsanTSDGet(); + AsanThreadContext *context = + reinterpret_cast(AsanTSDGet()); if (!context) { if (SANITIZER_ANDROID) { // On Android, libc constructor is called _after_ asan_init, and cleans up @@ -222,7 +268,7 @@ AsanThread *GetCurrentThread() { void SetCurrentThread(AsanThread *t) { CHECK(t->context()); - if (flags()->verbosity >= 2) { + if (common_flags()->verbosity >= 2) { Report("SetCurrentThread: %p for thread %p\n", t->context(), (void*)GetThreadSelf()); } @@ -244,6 +290,20 @@ AsanThread *FindThreadByStackAddress(uptr addr) { (void *)addr)); return tctx ? tctx->thread : 0; } + +void EnsureMainThreadIDIsCorrect() { + AsanThreadContext *context = + reinterpret_cast(AsanTSDGet()); + if (context && (context->tid == 0)) + context->os_id = GetTid(); +} + +__asan::AsanThread *GetAsanThreadByOsIDLocked(uptr os_id) { + __asan::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>( + __asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id)); + if (!context) return 0; + return context->thread; +} } // namespace __asan // --- Implementation of LSan-specific functions --- {{{1 @@ -251,8 +311,23 @@ namespace __lsan { bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end, uptr *tls_begin, uptr *tls_end, uptr *cache_begin, uptr *cache_end) { - // FIXME: Stub. - return false; + __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id); + if (!t) return false; + *stack_begin = t->stack_bottom(); + *stack_end = t->stack_top(); + *tls_begin = t->tls_begin(); + *tls_end = t->tls_end(); + // ASan doesn't keep allocator caches in TLS, so these are unused. + *cache_begin = 0; + *cache_end = 0; + return true; +} + +void ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback, + void *arg) { + __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id); + if (t && t->has_fake_stack()) + t->fake_stack()->ForEachFakeFrame(callback, arg); } void LockThreadRegistry() { @@ -262,4 +337,8 @@ void LockThreadRegistry() { void UnlockThreadRegistry() { __asan::asanThreadRegistry().Unlock(); } + +void EnsureMainThreadIDIsCorrect() { + __asan::EnsureMainThreadIDIsCorrect(); +} } // namespace __lsan diff --git a/lib/asan/asan_thread.h b/lib/asan/asan_thread.h index 14062b62f751..11771ecd09f0 100644 --- a/lib/asan/asan_thread.h +++ b/lib/asan/asan_thread.h @@ -19,6 +19,7 @@ #include "asan_fake_stack.h" #include "asan_stack.h" #include "asan_stats.h" +#include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_thread_registry.h" @@ -36,11 +37,13 @@ class AsanThreadContext : public ThreadContextBase { explicit AsanThreadContext(int tid) : ThreadContextBase(tid), announced(false), + destructor_iterations(kPthreadDestructorIterations), + stack_id(0), thread(0) { - internal_memset(&stack, 0, sizeof(stack)); } bool announced; - StackTrace stack; + u8 destructor_iterations; + u32 stack_id; AsanThread *thread; void OnCreated(void *arg); @@ -48,7 +51,7 @@ class AsanThreadContext : public ThreadContextBase { }; // AsanThreadContext objects are never freed, so we need many of them. -COMPILER_CHECK(sizeof(AsanThreadContext) <= 4096); +COMPILER_CHECK(sizeof(AsanThreadContext) <= 256); // AsanThread are stored in TSD and destroyed when the thread dies. class AsanThread { @@ -62,7 +65,9 @@ class AsanThread { uptr stack_top() { return stack_top_; } uptr stack_bottom() { return stack_bottom_; } - uptr stack_size() { return stack_top_ - stack_bottom_; } + uptr stack_size() { return stack_size_; } + uptr tls_begin() { return tls_begin_; } + uptr tls_end() { return tls_end_; } u32 tid() { return context_->tid; } AsanThreadContext *context() { return context_; } void set_context(AsanThreadContext *context) { context_ = context; } @@ -73,23 +78,68 @@ class AsanThread { return addr >= stack_bottom_ && addr < stack_top_; } - FakeStack &fake_stack() { return fake_stack_; } + void DeleteFakeStack() { + if (!fake_stack_) return; + FakeStack *t = fake_stack_; + fake_stack_ = 0; + SetTLSFakeStack(0); + t->Destroy(); + } + + bool has_fake_stack() { + return (reinterpret_cast(fake_stack_) > 1); + } + + FakeStack *fake_stack() { + if (!__asan_option_detect_stack_use_after_return) + return 0; + if (!has_fake_stack()) + return AsyncSignalSafeLazyInitFakeStack(); + return fake_stack_; + } + + // True is this thread is currently unwinding stack (i.e. collecting a stack + // trace). Used to prevent deadlocks on platforms where libc unwinder calls + // malloc internally. See PR17116 for more details. + bool isUnwinding() const { return unwinding; } + void setUnwinding(bool b) { unwinding = b; } + AsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; } AsanStats &stats() { return stats_; } private: - AsanThread() {} - void SetThreadStackTopAndBottom(); - void ClearShadowForThreadStack(); + AsanThread() : unwinding(false) {} + void SetThreadStackAndTls(); + void ClearShadowForThreadStackAndTLS(); + FakeStack *AsyncSignalSafeLazyInitFakeStack(); + AsanThreadContext *context_; thread_callback_t start_routine_; void *arg_; uptr stack_top_; uptr stack_bottom_; + // stack_size_ == stack_top_ - stack_bottom_; + // It needs to be set in a async-signal-safe manner. + uptr stack_size_; + uptr tls_begin_; + uptr tls_end_; - FakeStack fake_stack_; + FakeStack *fake_stack_; AsanThreadLocalMallocStorage malloc_storage_; AsanStats stats_; + bool unwinding; +}; + +// ScopedUnwinding is a scope for stacktracing member of a context +class ScopedUnwinding { + public: + explicit ScopedUnwinding(AsanThread *t) : thread(t) { + t->setUnwinding(true); + } + ~ScopedUnwinding() { thread->setUnwinding(false); } + + private: + AsanThread *thread; }; struct CreateThreadContextArgs { @@ -109,6 +159,8 @@ void SetCurrentThread(AsanThread *t); u32 GetCurrentTidOrInvalid(); AsanThread *FindThreadByStackAddress(uptr addr); +// Used to handle fork(). +void EnsureMainThreadIDIsCorrect(); } // namespace __asan #endif // ASAN_THREAD_H diff --git a/lib/asan/asan_win.cc b/lib/asan/asan_win.cc index f74de7227ed2..9e66b3417a1e 100644 --- a/lib/asan/asan_win.cc +++ b/lib/asan/asan_win.cc @@ -25,6 +25,14 @@ #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_mutex.h" +extern "C" { + SANITIZER_INTERFACE_ATTRIBUTE + int __asan_should_detect_stack_use_after_return() { + __asan_init(); + return __asan_option_detect_stack_use_after_return; + } +} + namespace __asan { // ---------------------- Stacktraces, symbols, etc. ---------------- {{{1 @@ -52,6 +60,9 @@ void AsanTSDSet(void *tsd) { fake_tsd = tsd; } +void PlatformTSDDtor(void *tsd) { + AsanThread::TSDDtor(tsd); +} // ---------------------- Various stuff ---------------- {{{1 void MaybeReexec() { // No need to re-exec on Windows. diff --git a/lib/asan/lit_tests/32bitConfig/lit.site.cfg.in b/lib/asan/lit_tests/32bitConfig/lit.site.cfg.in new file mode 100644 index 000000000000..faef4e8c9b17 --- /dev/null +++ b/lib/asan/lit_tests/32bitConfig/lit.site.cfg.in @@ -0,0 +1,13 @@ +## Autogenerated by LLVM/Clang configuration. +# Do not edit! + +# Load common config for all compiler-rt lit tests. +lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured") + +# Tool-specific config options. +config.asan_source_dir = "@ASAN_SOURCE_DIR@" +config.bits = "32" + +# Load tool-specific config that would do the real work. +lit_config.load_config(config, "@ASAN_SOURCE_DIR@/lit_tests/lit.cfg") + diff --git a/lib/asan/lit_tests/64bitConfig/lit.site.cfg.in b/lib/asan/lit_tests/64bitConfig/lit.site.cfg.in new file mode 100644 index 000000000000..a35994484d5f --- /dev/null +++ b/lib/asan/lit_tests/64bitConfig/lit.site.cfg.in @@ -0,0 +1,12 @@ +## Autogenerated by LLVM/Clang configuration. +# Do not edit! + +# Load common config for all compiler-rt lit tests. +lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured") + +# Tool-specific config options. +config.asan_source_dir = "@ASAN_SOURCE_DIR@" +config.bits = "64" + +# Load tool-specific config that would do the real work. +lit_config.load_config(config, "@ASAN_SOURCE_DIR@/lit_tests/lit.cfg") diff --git a/lib/asan/lit_tests/CMakeLists.txt b/lib/asan/lit_tests/CMakeLists.txt index d2420b50da83..72a3f5439b70 100644 --- a/lib/asan/lit_tests/CMakeLists.txt +++ b/lib/asan/lit_tests/CMakeLists.txt @@ -2,8 +2,13 @@ set(ASAN_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/..) set(ASAN_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/..) configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in - ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg + ${CMAKE_CURRENT_SOURCE_DIR}/64bitConfig/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/64bitConfig/lit.site.cfg + ) + +configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/32bitConfig/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig/lit.site.cfg ) configure_lit_site_cfg( @@ -12,21 +17,26 @@ configure_lit_site_cfg( ) if(COMPILER_RT_CAN_EXECUTE_TESTS) + set(ASAN_TESTSUITES) + if(CAN_TARGET_i386) + list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig) + endif() + if(CAN_TARGET_x86_64 OR CAN_TARGET_powerpc64) + list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/64bitConfig) + endif() # Run ASan tests only if we're sure we may produce working binaries. set(ASAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS} - ${ASAN_RUNTIME_LIBRARIES} - asan_blacklist) + asan_runtime_libraries) set(ASAN_TEST_PARAMS - asan_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg - ) + asan_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg) if(LLVM_INCLUDE_TESTS) list(APPEND ASAN_TEST_DEPS AsanUnitTests) + list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit) endif() add_lit_testsuite(check-asan "Running the AddressSanitizer tests" - ${CMAKE_CURRENT_BINARY_DIR} + ${ASAN_TESTSUITES} PARAMS ${ASAN_TEST_PARAMS} - DEPENDS ${ASAN_TEST_DEPS} - ) + DEPENDS ${ASAN_TEST_DEPS}) set_target_properties(check-asan PROPERTIES FOLDER "ASan tests") endif() diff --git a/lib/asan/lit_tests/Darwin/interface_symbols_darwin.c b/lib/asan/lit_tests/Darwin/interface_symbols_darwin.c deleted file mode 100644 index 3fca6e915324..000000000000 --- a/lib/asan/lit_tests/Darwin/interface_symbols_darwin.c +++ /dev/null @@ -1,39 +0,0 @@ -// Check the presense of interface symbols in the ASan runtime dylib. -// If you're changing this file, please also change -// ../Linux/interface_symbols.c - -// RUN: %clang -fsanitize=address -dead_strip -O2 %s -o %t.exe -// RUN: rm -f %t.symbols %t.interface - -// RUN: nm -g `otool -L %t.exe | grep "asan_osx_dynamic.dylib" | \ -// RUN: tr -d '\011' | \ -// RUN: sed "s/.dylib.*/.dylib/"` \ -// RUN: | grep " T " | sed "s/.* T //" \ -// RUN: | grep "__asan_" | sed "s/___asan_/__asan_/" \ -// RUN: | grep -v "__asan_malloc_hook" \ -// RUN: | grep -v "__asan_free_hook" \ -// RUN: | grep -v "__asan_symbolize" \ -// RUN: | grep -v "__asan_default_options" \ -// RUN: | grep -v "__asan_on_error" > %t.symbols - -// RUN: cat %p/../../asan_interface_internal.h \ -// RUN: | sed "s/\/\/.*//" | sed "s/typedef.*//" \ -// RUN: | grep -v "OPTIONAL" \ -// RUN: | grep "__asan_.*(" | sed "s/.* __asan_/__asan_/;s/(.*//" \ -// RUN: > %t.interface -// RUN: echo __asan_report_load1 >> %t.interface -// RUN: echo __asan_report_load2 >> %t.interface -// RUN: echo __asan_report_load4 >> %t.interface -// RUN: echo __asan_report_load8 >> %t.interface -// RUN: echo __asan_report_load16 >> %t.interface -// RUN: echo __asan_report_store1 >> %t.interface -// RUN: echo __asan_report_store2 >> %t.interface -// RUN: echo __asan_report_store4 >> %t.interface -// RUN: echo __asan_report_store8 >> %t.interface -// RUN: echo __asan_report_store16 >> %t.interface -// RUN: echo __asan_report_load_n >> %t.interface -// RUN: echo __asan_report_store_n >> %t.interface - -// RUN: cat %t.interface | sort -u | diff %t.symbols - - -int main() { return 0; } diff --git a/lib/asan/lit_tests/Darwin/lit.local.cfg b/lib/asan/lit_tests/Darwin/lit.local.cfg deleted file mode 100644 index a85dfcd24c08..000000000000 --- a/lib/asan/lit_tests/Darwin/lit.local.cfg +++ /dev/null @@ -1,9 +0,0 @@ -def getRoot(config): - if not config.parent: - return config - return getRoot(config.parent) - -root = getRoot(config) - -if root.host_os not in ['Darwin']: - config.unsupported = True diff --git a/lib/asan/lit_tests/Darwin/reexec-insert-libraries-env.cc b/lib/asan/lit_tests/Darwin/reexec-insert-libraries-env.cc deleted file mode 100644 index 40a459fd84db..000000000000 --- a/lib/asan/lit_tests/Darwin/reexec-insert-libraries-env.cc +++ /dev/null @@ -1,20 +0,0 @@ -// Make sure ASan doesn't hang in an exec loop if DYLD_INSERT_LIBRARIES is set. -// This is a regression test for -// https://code.google.com/p/address-sanitizer/issues/detail?id=159 - -// RUN: %clangxx_asan -m64 %s -o %t -// RUN: %clangxx -m64 %p/../SharedLibs/darwin-dummy-shared-lib-so.cc \ -// RUN: -dynamiclib -o darwin-dummy-shared-lib-so.dylib - -// FIXME: the following command line may hang in the case of a regression. -// RUN: DYLD_INSERT_LIBRARIES=darwin-dummy-shared-lib-so.dylib \ -// RUN: %t 2>&1 | FileCheck %s || exit 1 -#include -#include - -int main() { - const char kEnvName[] = "DYLD_INSERT_LIBRARIES"; - printf("%s=%s\n", kEnvName, getenv(kEnvName)); - // CHECK: {{DYLD_INSERT_LIBRARIES=.*darwin-dummy-shared-lib-so.dylib.*}} - return 0; -} diff --git a/lib/asan/lit_tests/Darwin/unset-insert-libraries-on-exec.cc b/lib/asan/lit_tests/Darwin/unset-insert-libraries-on-exec.cc deleted file mode 100644 index cf89949cf942..000000000000 --- a/lib/asan/lit_tests/Darwin/unset-insert-libraries-on-exec.cc +++ /dev/null @@ -1,20 +0,0 @@ -// Make sure ASan removes the runtime library from DYLD_INSERT_LIBRARIES before -// executing other programs. - -// RUN: %clangxx_asan -m64 %s -o %t -// RUN: %clangxx -m64 %p/../SharedLibs/darwin-dummy-shared-lib-so.cc \ -// RUN: -dynamiclib -o darwin-dummy-shared-lib-so.dylib - -// Make sure DYLD_INSERT_LIBRARIES doesn't contain the runtime library before -// execl(). - -// RUN: %t >/dev/null 2>&1 -// RUN: DYLD_INSERT_LIBRARIES=darwin-dummy-shared-lib-so.dylib \ -// RUN: %t 2>&1 | FileCheck %s || exit 1 -#include -int main() { - execl("/bin/bash", "/bin/bash", "-c", - "echo DYLD_INSERT_LIBRARIES=$DYLD_INSERT_LIBRARIES", NULL); - // CHECK: {{DYLD_INSERT_LIBRARIES=.*darwin-dummy-shared-lib-so.dylib.*}} - return 0; -} diff --git a/lib/asan/lit_tests/Helpers/blacklist-extra.cc b/lib/asan/lit_tests/Helpers/blacklist-extra.cc deleted file mode 100644 index 627115cdda2b..000000000000 --- a/lib/asan/lit_tests/Helpers/blacklist-extra.cc +++ /dev/null @@ -1,5 +0,0 @@ -// This function is broken, but this file is blacklisted -int externalBrokenFunction(int argc) { - char x[10] = {0}; - return x[argc * 10]; // BOOM -} diff --git a/lib/asan/lit_tests/Helpers/init-order-atexit-extra.cc b/lib/asan/lit_tests/Helpers/init-order-atexit-extra.cc deleted file mode 100644 index e4189d19d099..000000000000 --- a/lib/asan/lit_tests/Helpers/init-order-atexit-extra.cc +++ /dev/null @@ -1,16 +0,0 @@ -#include - -class C { - public: - C() { value = 42; } - ~C() { } - int value; -}; - -C c; - -void AccessC() { - printf("C value: %d\n", c.value); -} - -int main() { return 0; } diff --git a/lib/asan/lit_tests/Helpers/initialization-blacklist-extra.cc b/lib/asan/lit_tests/Helpers/initialization-blacklist-extra.cc deleted file mode 100644 index 09aed2112d5e..000000000000 --- a/lib/asan/lit_tests/Helpers/initialization-blacklist-extra.cc +++ /dev/null @@ -1,15 +0,0 @@ -int zero_init() { return 0; } -int badGlobal = zero_init(); -int readBadGlobal() { return badGlobal; } - -namespace badNamespace { -class BadClass { - public: - BadClass() { value = 0; } - int value; -}; -// Global object with non-trivial constructor. -BadClass bad_object; -} // namespace badNamespace - -int accessBadObject() { return badNamespace::bad_object.value; } diff --git a/lib/asan/lit_tests/Helpers/initialization-blacklist-extra2.cc b/lib/asan/lit_tests/Helpers/initialization-blacklist-extra2.cc deleted file mode 100644 index 69455a0a6fc9..000000000000 --- a/lib/asan/lit_tests/Helpers/initialization-blacklist-extra2.cc +++ /dev/null @@ -1,4 +0,0 @@ -int zero_init(); -int badSrcGlobal = zero_init(); -int readBadSrcGlobal() { return badSrcGlobal; } - diff --git a/lib/asan/lit_tests/Helpers/initialization-blacklist.txt b/lib/asan/lit_tests/Helpers/initialization-blacklist.txt deleted file mode 100644 index fa4a83667f4b..000000000000 --- a/lib/asan/lit_tests/Helpers/initialization-blacklist.txt +++ /dev/null @@ -1,3 +0,0 @@ -global-init:*badGlobal* -global-init-type:*badNamespace::BadClass* -global-init-src:*initialization-blacklist-extra2.cc diff --git a/lib/asan/lit_tests/Helpers/initialization-bug-extra.cc b/lib/asan/lit_tests/Helpers/initialization-bug-extra.cc deleted file mode 100644 index 3c4cb411defa..000000000000 --- a/lib/asan/lit_tests/Helpers/initialization-bug-extra.cc +++ /dev/null @@ -1,5 +0,0 @@ -// This file simply declares a dynamically initialized var by the name of 'y'. -int initY() { - return 5; -} -int y = initY(); diff --git a/lib/asan/lit_tests/Helpers/initialization-bug-extra2.cc b/lib/asan/lit_tests/Helpers/initialization-bug-extra2.cc deleted file mode 100644 index a3d8f190e58b..000000000000 --- a/lib/asan/lit_tests/Helpers/initialization-bug-extra2.cc +++ /dev/null @@ -1,6 +0,0 @@ -// 'z' is dynamically initialized global from different TU. -extern int z; -int __attribute__((noinline)) initY() { - return z + 1; -} -int y = initY(); diff --git a/lib/asan/lit_tests/Helpers/initialization-constexpr-extra.cc b/lib/asan/lit_tests/Helpers/initialization-constexpr-extra.cc deleted file mode 100644 index b32466a981b3..000000000000 --- a/lib/asan/lit_tests/Helpers/initialization-constexpr-extra.cc +++ /dev/null @@ -1,3 +0,0 @@ -// Constexpr: -int getCoolestInteger(); -static int coolest_integer = getCoolestInteger(); diff --git a/lib/asan/lit_tests/Helpers/initialization-nobug-extra.cc b/lib/asan/lit_tests/Helpers/initialization-nobug-extra.cc deleted file mode 100644 index 886165affd76..000000000000 --- a/lib/asan/lit_tests/Helpers/initialization-nobug-extra.cc +++ /dev/null @@ -1,9 +0,0 @@ -// Linker initialized: -int getAB(); -static int ab = getAB(); -// Function local statics: -int countCalls(); -static int one = countCalls(); -// Trivial constructor, non-trivial destructor: -int getStructWithDtorValue(); -static int val = getStructWithDtorValue(); diff --git a/lib/asan/lit_tests/Helpers/lit.local.cfg b/lib/asan/lit_tests/Helpers/lit.local.cfg deleted file mode 100644 index 2fc4d99456b0..000000000000 --- a/lib/asan/lit_tests/Helpers/lit.local.cfg +++ /dev/null @@ -1,3 +0,0 @@ -# Sources in this directory are helper files for tests which test functionality -# involving multiple translation units. -config.suffixes = [] diff --git a/lib/asan/lit_tests/Linux/asan_prelink_test.cc b/lib/asan/lit_tests/Linux/asan_prelink_test.cc deleted file mode 100644 index c209c39c8c42..000000000000 --- a/lib/asan/lit_tests/Linux/asan_prelink_test.cc +++ /dev/null @@ -1,28 +0,0 @@ -// Test if asan works with prelink. -// It does not actually use prelink, but relies on ld's flag -Ttext-segment -// or gold's flag -Ttext (we try the first flag first, if that fails we -// try the second flag). -// -// RUN: %clangxx_asan -m64 -c %s -o %t.o -// RUN: %clangxx_asan -m64 -DBUILD_SO=1 -fPIC -shared %s -o %t.so -Wl,-Ttext-segment=0x3600000000 ||\ -// RUN: %clangxx_asan -m64 -DBUILD_SO=1 -fPIC -shared %s -o %t.so -Wl,-Ttext=0x3600000000 -// RUN: %clangxx_asan -m64 %t.o %t.so -Wl,-R. -o %t -// RUN: ASAN_OPTIONS=verbosity=1 %t 2>&1 | FileCheck %s - -// REQUIRES: x86_64-supported-target -#if BUILD_SO -int G; -int *getG() { - return &G; -} -#else -#include -extern int *getG(); -int main(int argc, char **argv) { - long p = (long)getG(); - printf("SO mapped at %lx\n", p & ~0xffffffffUL); - *getG() = 0; -} -#endif -// CHECK: 0x003000000000, 0x004fffffffff{{.*}} MidMem -// CHECK: SO mapped at 3600000000 diff --git a/lib/asan/lit_tests/Linux/clone_test.cc b/lib/asan/lit_tests/Linux/clone_test.cc deleted file mode 100644 index ca13b22425f2..000000000000 --- a/lib/asan/lit_tests/Linux/clone_test.cc +++ /dev/null @@ -1,48 +0,0 @@ -// Regression test for: -// http://code.google.com/p/address-sanitizer/issues/detail?id=37 - -// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t | FileCheck %s -// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t | FileCheck %s -// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t | FileCheck %s -// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t | FileCheck %s -// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t | FileCheck %s -// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t | FileCheck %s -// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t | FileCheck %s -// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t | FileCheck %s - -#include -#include -#include -#include -#include -#include - -int Child(void *arg) { - char x[32] = {0}; // Stack gets poisoned. - printf("Child: %p\n", x); - _exit(1); // NoReturn, stack will remain unpoisoned unless we do something. -} - -int main(int argc, char **argv) { - const int kStackSize = 1 << 20; - char child_stack[kStackSize + 1]; - char *sp = child_stack + kStackSize; // Stack grows down. - printf("Parent: %p\n", sp); - pid_t clone_pid = clone(Child, sp, CLONE_FILES | CLONE_VM, NULL, 0, 0, 0); - int status; - pid_t wait_result = waitpid(clone_pid, &status, __WCLONE); - if (wait_result < 0) { - perror("waitpid"); - return 0; - } - if (wait_result == clone_pid && WIFEXITED(status)) { - // Make sure the child stack was indeed unpoisoned. - for (int i = 0; i < kStackSize; i++) - child_stack[i] = i; - int ret = child_stack[argc - 1]; - printf("PASSED\n"); - // CHECK: PASSED - return ret; - } - return 0; -} diff --git a/lib/asan/lit_tests/Linux/glob.cc b/lib/asan/lit_tests/Linux/glob.cc deleted file mode 100644 index e05228ff39e3..000000000000 --- a/lib/asan/lit_tests/Linux/glob.cc +++ /dev/null @@ -1,30 +0,0 @@ -// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t %p 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t %p 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t %p 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t %p 2>&1 | FileCheck %s - -#include -#include -#include -#include -#include -#include - - -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])); - printf("PASS\n"); - // CHECK: PASS - return 0; -} diff --git a/lib/asan/lit_tests/Linux/glob_test_root/aa b/lib/asan/lit_tests/Linux/glob_test_root/aa deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/lib/asan/lit_tests/Linux/glob_test_root/ab b/lib/asan/lit_tests/Linux/glob_test_root/ab deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/lib/asan/lit_tests/Linux/glob_test_root/ba b/lib/asan/lit_tests/Linux/glob_test_root/ba deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/lib/asan/lit_tests/Linux/heavy_uar_test.cc b/lib/asan/lit_tests/Linux/heavy_uar_test.cc deleted file mode 100644 index c0f4560fb4e7..000000000000 --- a/lib/asan/lit_tests/Linux/heavy_uar_test.cc +++ /dev/null @@ -1,55 +0,0 @@ -// RUN: %clangxx_asan -fsanitize=use-after-return -m64 -O0 %s -o %t && \ -// RUN: %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -fsanitize=use-after-return -m64 -O2 %s -o %t && \ -// RUN: %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -fsanitize=use-after-return -m32 -O2 %s -o %t && \ -// RUN: %t 2>&1 | %symbolize | FileCheck %s - -#include -#include -#include - -__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 -__attribute__((noinline)) -void RecuriveFunctionWithStackFrame(int depth) { - if (depth <= 0) return; - char x[kFrameSize]; - x[0] = depth; - pretend_to_do_something(x); - RecuriveFunctionWithStackFrame(depth - 1); -} - -int main(int argc, char **argv) { - int n_iter = argc >= 2 ? atoi(argv[1]) : 1000; - int depth = argc >= 3 ? atoi(argv[2]) : 500; - for (int i = 0; i < n_iter; i++) { - RecuriveFunctionWithStackFrame<10>(depth); - RecuriveFunctionWithStackFrame<100>(depth); - RecuriveFunctionWithStackFrame<500>(depth); - RecuriveFunctionWithStackFrame<1024>(depth); - RecuriveFunctionWithStackFrame<2000>(depth); - RecuriveFunctionWithStackFrame<5000>(depth); - RecuriveFunctionWithStackFrame<10000>(depth); - } - char *stale_stack = LeakStack(); - RecuriveFunctionWithStackFrame<1024>(10); - stale_stack[100]++; - // CHECK: ERROR: AddressSanitizer: stack-use-after-return on address - // CHECK: is located in stack of thread T0 at offset 132 in frame - // CHECK: in LeakStack(){{.*}}heavy_uar_test.cc: - // CHECK: [32, 1056) 'x' - return 0; -} diff --git a/lib/asan/lit_tests/Linux/initialization-bug-any-order.cc b/lib/asan/lit_tests/Linux/initialization-bug-any-order.cc deleted file mode 100644 index 4f41dda18128..000000000000 --- a/lib/asan/lit_tests/Linux/initialization-bug-any-order.cc +++ /dev/null @@ -1,38 +0,0 @@ -// Test to make sure basic initialization order errors are caught. -// Check that on Linux initialization order bugs are caught -// independently on order in which we list source files (if we specify -// strict init-order checking). - -// RUN: %clangxx_asan -m64 -O0 %s %p/../Helpers/initialization-bug-extra.cc -o %t -// RUN: ASAN_OPTIONS=check_initialization_order=true:strict_init_order=true %t 2>&1 \ -// RUN: | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m64 -O0 %p/../Helpers/initialization-bug-extra.cc %s -o %t -// RUN: ASAN_OPTIONS=check_initialization_order=true:strict_init_order=true %t 2>&1 \ -// RUN: | %symbolize | FileCheck %s - -// Do not test with optimization -- the error may be optimized away. - -#include - -// 'y' is a dynamically initialized global residing in a different TU. This -// dynamic initializer will read the value of 'y' before main starts. The -// result is undefined behavior, which should be caught by initialization order -// checking. -extern int y; -int __attribute__((noinline)) initX() { - return y + 1; - // CHECK: {{AddressSanitizer: initialization-order-fiasco}} - // CHECK: {{READ of size .* at 0x.* thread T0}} - // CHECK: {{#0 0x.* in .*initX.* .*initialization-bug-any-order.cc:}}[[@LINE-3]] - // CHECK: {{0x.* is located 0 bytes inside of global variable .*y.*}} -} - -// This initializer begins our initialization order problems. -static int x = initX(); - -int main() { - // ASan should have caused an exit before main runs. - printf("PASS\n"); - // CHECK-NOT: PASS - return 0; -} diff --git a/lib/asan/lit_tests/Linux/interception_failure_test.cc b/lib/asan/lit_tests/Linux/interception_failure_test.cc deleted file mode 100644 index dfad909f528c..000000000000 --- a/lib/asan/lit_tests/Linux/interception_failure_test.cc +++ /dev/null @@ -1,26 +0,0 @@ -// If user provides his own libc functions, ASan doesn't -// intercept these functions. - -// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | FileCheck %s -#include -#include - -extern "C" long strtol(const char *nptr, char **endptr, int base) { - fprintf(stderr, "my_strtol_interceptor\n"); - return 0; -} - -int main() { - char *x = (char*)malloc(10 * sizeof(char)); - free(x); - return (int)strtol(x, 0, 10); - // CHECK: my_strtol_interceptor - // CHECK-NOT: heap-use-after-free -} diff --git a/lib/asan/lit_tests/Linux/interception_malloc_test.cc b/lib/asan/lit_tests/Linux/interception_malloc_test.cc deleted file mode 100644 index 8f66788e9a82..000000000000 --- a/lib/asan/lit_tests/Linux/interception_malloc_test.cc +++ /dev/null @@ -1,27 +0,0 @@ -// ASan interceptor can be accessed with __interceptor_ prefix. - -// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | FileCheck %s -#include -#include -#include - -extern "C" void *__interceptor_malloc(size_t size); -extern "C" void *malloc(size_t size) { - write(2, "malloc call\n", sizeof("malloc call\n") - 1); - return __interceptor_malloc(size); -} - -int main() { - char *x = (char*)malloc(10 * sizeof(char)); - free(x); - return (int)strtol(x, 0, 10); - // CHECK: malloc call - // CHECK: heap-use-after-free -} diff --git a/lib/asan/lit_tests/Linux/interception_test.cc b/lib/asan/lit_tests/Linux/interception_test.cc deleted file mode 100644 index 94fb499f2f87..000000000000 --- a/lib/asan/lit_tests/Linux/interception_test.cc +++ /dev/null @@ -1,26 +0,0 @@ -// ASan interceptor can be accessed with __interceptor_ prefix. - -// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | FileCheck %s -#include -#include - -extern "C" long __interceptor_strtol(const char *nptr, char **endptr, int base); -extern "C" long strtol(const char *nptr, char **endptr, int base) { - fprintf(stderr, "my_strtol_interceptor\n"); - return __interceptor_strtol(nptr, endptr, base); -} - -int main() { - char *x = (char*)malloc(10 * sizeof(char)); - free(x); - return (int)strtol(x, 0, 10); - // CHECK: my_strtol_interceptor - // CHECK: heap-use-after-free -} diff --git a/lib/asan/lit_tests/Linux/interface_symbols_linux.c b/lib/asan/lit_tests/Linux/interface_symbols_linux.c deleted file mode 100644 index 4134c8744043..000000000000 --- a/lib/asan/lit_tests/Linux/interface_symbols_linux.c +++ /dev/null @@ -1,34 +0,0 @@ -// Check the presense of interface symbols in compiled file. - -// RUN: %clang -fsanitize=address -O2 %s -o %t.exe -// RUN: nm -D %t.exe | grep " T " | sed "s/.* T //" \ -// RUN: | grep "__asan_" | sed "s/___asan_/__asan_/" \ -// RUN: | grep -v "__asan_malloc_hook" \ -// RUN: | grep -v "__asan_free_hook" \ -// RUN: | grep -v "__asan_symbolize" \ -// RUN: | grep -v "__asan_default_options" \ -// RUN: | grep -v "__asan_on_error" > %t.symbols -// RUN: cat %p/../../asan_interface_internal.h \ -// RUN: | sed "s/\/\/.*//" | sed "s/typedef.*//" \ -// RUN: | grep -v "OPTIONAL" \ -// RUN: | grep "__asan_.*(" | sed "s/.* __asan_/__asan_/;s/(.*//" \ -// RUN: > %t.interface -// RUN: echo __asan_report_load1 >> %t.interface -// RUN: echo __asan_report_load2 >> %t.interface -// RUN: echo __asan_report_load4 >> %t.interface -// RUN: echo __asan_report_load8 >> %t.interface -// RUN: echo __asan_report_load16 >> %t.interface -// RUN: echo __asan_report_store1 >> %t.interface -// RUN: echo __asan_report_store2 >> %t.interface -// RUN: echo __asan_report_store4 >> %t.interface -// RUN: echo __asan_report_store8 >> %t.interface -// RUN: echo __asan_report_store16 >> %t.interface -// RUN: echo __asan_report_load_n >> %t.interface -// RUN: echo __asan_report_store_n >> %t.interface -// RUN: cat %t.interface | sort -u | diff %t.symbols - - -// FIXME: nm -D on powerpc somewhy shows ASan interface symbols residing -// in "initialized data section". -// REQUIRES: x86_64-supported-target,i386-supported-target - -int main() { return 0; } diff --git a/lib/asan/lit_tests/Linux/lit.local.cfg b/lib/asan/lit_tests/Linux/lit.local.cfg deleted file mode 100644 index 57271b8078a4..000000000000 --- a/lib/asan/lit_tests/Linux/lit.local.cfg +++ /dev/null @@ -1,9 +0,0 @@ -def getRoot(config): - if not config.parent: - return config - return getRoot(config.parent) - -root = getRoot(config) - -if root.host_os not in ['Linux']: - config.unsupported = True diff --git a/lib/asan/lit_tests/Linux/malloc-in-qsort.cc b/lib/asan/lit_tests/Linux/malloc-in-qsort.cc deleted file mode 100644 index ee2e81f0d2ab..000000000000 --- a/lib/asan/lit_tests/Linux/malloc-in-qsort.cc +++ /dev/null @@ -1,54 +0,0 @@ -// RUN: %clangxx_asan -m64 -O2 %s -o %t -// RUN: ASAN_OPTIONS=fast_unwind_on_malloc=1 %t 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK-FAST -// RUN: ASAN_OPTIONS=fast_unwind_on_malloc=0 %t 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK-SLOW - -// Test how well we unwind in presence of qsort in the stack -// (i.e. if we can unwind through a function compiled w/o frame pointers). -// https://code.google.com/p/address-sanitizer/issues/detail?id=137 - -// Fast unwinder is only avaliable on x86_64 and i386. -// REQUIRES: x86_64-supported-target - -#include -#include - -int *GlobalPtr; - -extern "C" { -int QsortCallback(const void *a, const void *b) { - char *x = (char*)a; - char *y = (char*)b; - printf("Calling QsortCallback\n"); - GlobalPtr = new int[10]; - return (int)*x - (int)*y; -} - -__attribute__((noinline)) -void MyQsort(char *a, size_t size) { - printf("Calling qsort\n"); - qsort(a, size, sizeof(char), QsortCallback); - printf("Done\n"); // Avoid tail call. -} -} // extern "C" - -int main() { - char a[2] = {1, 2}; - MyQsort(a, 2); - return GlobalPtr[10]; -} - -// Fast unwind: can not unwind through qsort. -// FIXME: this test does not properly work with slow unwind yet. - -// CHECK-FAST: ERROR: AddressSanitizer: heap-buffer-overflow -// CHECK-FAST: is located 0 bytes to the right -// CHECK-FAST: #0{{.*}}operator new -// CHECK-FAST-NEXT: #1{{.*}}QsortCallback -// CHECK-FAST-NOT: MyQsort -// -// CHECK-SLOW: ERROR: AddressSanitizer: heap-buffer-overflow -// CHECK-SLOW: is located 0 bytes to the right -// CHECK-SLOW: #0{{.*}}operator new -// CHECK-SLOW-NEXT: #1{{.*}}QsortCallback -// CHECK-SLOW: #{{.*}}MyQsort -// CHECK-SLOW-NEXT: #{{.*}}main diff --git a/lib/asan/lit_tests/Linux/malloc_delete_mismatch.cc b/lib/asan/lit_tests/Linux/malloc_delete_mismatch.cc deleted file mode 100644 index f34b33a38fb3..000000000000 --- a/lib/asan/lit_tests/Linux/malloc_delete_mismatch.cc +++ /dev/null @@ -1,26 +0,0 @@ -// Check that we detect malloc/delete mismatch only if the approptiate flag -// is set. - -// RUN: %clangxx_asan -g %s -o %t 2>&1 -// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=1 %t 2>&1 | \ -// RUN: %symbolize | FileCheck %s - -// No error here. -// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=0 %t -#include - -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: -// CHECK-NEXT: #0{{.*}}malloc -// CHECK: #{{.*}}main -// CHECK: HINT: {{.*}} you may set ASAN_OPTIONS=alloc_dealloc_mismatch=0 diff --git a/lib/asan/lit_tests/Linux/overflow-in-qsort.cc b/lib/asan/lit_tests/Linux/overflow-in-qsort.cc deleted file mode 100644 index 8bc43ca0a5c3..000000000000 --- a/lib/asan/lit_tests/Linux/overflow-in-qsort.cc +++ /dev/null @@ -1,51 +0,0 @@ -// RUN: %clangxx_asan -m64 -O2 %s -o %t -// RUN: ASAN_OPTIONS=fast_unwind_on_fatal=1 %t 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK-FAST -// RUN: ASAN_OPTIONS=fast_unwind_on_fatal=0 %t 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK-SLOW - -// Test how well we unwind in presence of qsort in the stack -// (i.e. if we can unwind through a function compiled w/o frame pointers). -// https://code.google.com/p/address-sanitizer/issues/detail?id=137 - -// Fast unwinder is only avaliable on x86_64 and i386. -// REQUIRES: x86_64-supported-target - -#include -#include - -int global_array[10]; -volatile int one = 1; - -extern "C" { -int QsortCallback(const void *a, const void *b) { - char *x = (char*)a; - char *y = (char*)b; - printf("Calling QsortCallback\n"); - global_array[one * 10] = 0; // BOOM - return (int)*x - (int)*y; -} - -__attribute__((noinline)) -void MyQsort(char *a, size_t size) { - printf("Calling qsort\n"); - qsort(a, size, sizeof(char), QsortCallback); - printf("Done\n"); // Avoid tail call. -} -} // extern "C" - -int main() { - char a[2] = {1, 2}; - MyQsort(a, 2); -} - -// Fast unwind: can not unwind through qsort. - -// CHECK-FAST: ERROR: AddressSanitizer: global-buffer-overflow -// CHECK-FAST: #0{{.*}} in QsortCallback -// CHECK-FAST-NOT: MyQsort -// CHECK-FAST: is located 0 bytes to the right of global variable 'global_array - -// CHECK-SLOW: ERROR: AddressSanitizer: global-buffer-overflow -// CHECK-SLOW: #0{{.*}} in QsortCallback -// CHECK-SLOW: #{{.*}} in MyQsort -// CHECK-SLOW: #{{.*}} in main -// CHECK-SLOW: is located 0 bytes to the right of global variable 'global_array diff --git a/lib/asan/lit_tests/Linux/preinit_test.cc b/lib/asan/lit_tests/Linux/preinit_test.cc deleted file mode 100644 index 28e509472c0c..000000000000 --- a/lib/asan/lit_tests/Linux/preinit_test.cc +++ /dev/null @@ -1,27 +0,0 @@ -// RUN: %clangxx -DFUNC=zzzz %s -shared -o %t.so -fPIC -// RUN: %clangxx_asan -DFUNC=main %s -o %t -Wl,-R. %t.so -// RUN: %t - -// This test ensures that we call __asan_init early enough. -// We build a shared library w/o asan instrumentation -// and the binary with asan instrumentation. -// Both files include the same header (emulated by -DFUNC here) -// with C++ template magic which runs global initializer at library load time. -// The function get() is instrumented with asan, but called -// before the usual constructors are run. -// So, we must make sure that __asan_init is executed even earlier. -// -// See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56393 - -struct A { - int foo() const { return 0; } -}; -A get () { return A(); } -template struct O { - static A const e; -}; -template A const O ::e = get(); -int FUNC() { - return O::e.foo(); -} - diff --git a/lib/asan/lit_tests/Linux/rlimit_mmap_test.cc b/lib/asan/lit_tests/Linux/rlimit_mmap_test.cc deleted file mode 100644 index 86794756c76f..000000000000 --- a/lib/asan/lit_tests/Linux/rlimit_mmap_test.cc +++ /dev/null @@ -1,16 +0,0 @@ -// Check that we properly report mmap failure. -// RUN: %clangxx_asan %s -o %t && %t 2>&1 | FileCheck %s -#include -#include -#include -#include - -static volatile void *x; - -int main(int argc, char **argv) { - struct rlimit mmap_resource_limit = { 0, 0 }; - assert(0 == setrlimit(RLIMIT_AS, &mmap_resource_limit)); - x = malloc(10000000); -// CHECK: ERROR: Failed to mmap - return 0; -} diff --git a/lib/asan/lit_tests/Linux/swapcontext_test.cc b/lib/asan/lit_tests/Linux/swapcontext_test.cc deleted file mode 100644 index 47a8d9891f51..000000000000 --- a/lib/asan/lit_tests/Linux/swapcontext_test.cc +++ /dev/null @@ -1,94 +0,0 @@ -// Check that ASan plays well with easy cases of makecontext/swapcontext. - -// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | FileCheck %s -// -// This test is too sublte to try on non-x86 arch for now. -// REQUIRES: x86_64-supported-target,i386-supported-target - -#include -#include -#include - -ucontext_t orig_context; -ucontext_t child_context; - -const int kStackSize = 1 << 20; - -__attribute__((noinline)) -void Throw() { - throw 1; -} - -__attribute__((noinline)) -void ThrowAndCatch() { - try { - Throw(); - } catch(int a) { - printf("ThrowAndCatch: %d\n", a); - } -} - -void Child(int mode) { - char x[32] = {0}; // Stack gets poisoned. - printf("Child: %p\n", x); - ThrowAndCatch(); // Simulate __asan_handle_no_return(). - // (a) Do nothing, just return to parent function. - // (b) Jump into the original function. Stack remains poisoned unless we do - // something. - if (mode == 1) { - if (swapcontext(&child_context, &orig_context) < 0) { - perror("swapcontext"); - _exit(0); - } - } -} - -int Run(int arg, int mode, char *child_stack) { - printf("Child stack: %p\n", child_stack); - // Setup child context. - getcontext(&child_context); - child_context.uc_stack.ss_sp = child_stack; - child_context.uc_stack.ss_size = kStackSize / 2; - if (mode == 0) { - child_context.uc_link = &orig_context; - } - makecontext(&child_context, (void (*)())Child, 1, mode); - if (swapcontext(&orig_context, &child_context) < 0) { - perror("swapcontext"); - return 0; - } - // Touch childs's stack to make sure it's unpoisoned. - for (int i = 0; i < kStackSize; i++) { - child_stack[i] = i; - } - return child_stack[arg]; -} - -int main(int argc, char **argv) { - char stack[kStackSize + 1]; - // CHECK: WARNING: ASan doesn't fully support makecontext/swapcontext - int ret = 0; - ret += Run(argc - 1, 0, stack); - printf("Test1 passed\n"); - // CHECK: Test1 passed - ret += Run(argc - 1, 1, stack); - printf("Test2 passed\n"); - // CHECK: Test2 passed - char *heap = new char[kStackSize + 1]; - ret += Run(argc - 1, 0, heap); - printf("Test3 passed\n"); - // CHECK: Test3 passed - ret += Run(argc - 1, 1, heap); - printf("Test4 passed\n"); - // CHECK: Test4 passed - - delete [] heap; - return ret; -} diff --git a/lib/asan/lit_tests/Linux/syscalls.cc b/lib/asan/lit_tests/Linux/syscalls.cc deleted file mode 100644 index b2edcfb92375..000000000000 --- a/lib/asan/lit_tests/Linux/syscalls.cc +++ /dev/null @@ -1,22 +0,0 @@ -// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s - -#include -#include -#include -#include -#include - -#include - -/* 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_pre_recvmsg - return 0; -} diff --git a/lib/asan/lit_tests/Linux/time_null_regtest.cc b/lib/asan/lit_tests/Linux/time_null_regtest.cc deleted file mode 100644 index 975bca3d105a..000000000000 --- a/lib/asan/lit_tests/Linux/time_null_regtest.cc +++ /dev/null @@ -1,20 +0,0 @@ -// RUN: %clangxx_asan -m64 -O0 %s -fsanitize-address-zero-base-shadow -pie -o %t && %t 2>&1 | %symbolize | FileCheck %s - -// Zero-base shadow only works on x86_64 and i386. -// REQUIRES: x86_64-supported-target - -// A regression test for time(NULL), which caused ASan to crash in the -// zero-based shadow mode on Linux. -// FIXME: this test does not work on Darwin, because the code pages of the -// executable interleave with the zero-based shadow. - -#include -#include -#include - -int main() { - time_t t = time(NULL); - fprintf(stderr, "Time: %s\n", ctime(&t)); // NOLINT - // CHECK: {{Time: .* .* .*}} - return 0; -} diff --git a/lib/asan/lit_tests/Linux/zero-base-shadow.cc b/lib/asan/lit_tests/Linux/zero-base-shadow.cc deleted file mode 100644 index 682e7e8d7e59..000000000000 --- a/lib/asan/lit_tests/Linux/zero-base-shadow.cc +++ /dev/null @@ -1,31 +0,0 @@ -// RUN: %clangxx_asan -m64 -O0 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-64 < %t.out -// RUN: %clangxx_asan -m64 -O1 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-64 < %t.out -// RUN: %clangxx_asan -m64 -O2 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-64 < %t.out -// RUN: %clangxx_asan -m32 -O0 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-32 < %t.out -// RUN: %clangxx_asan -m32 -O1 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-32 < %t.out -// RUN: %clangxx_asan -m32 -O2 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-32 < %t.out - -// Zero-base shadow only works on x86_64 and i386. -// REQUIRES: x86_64-supported-target,i386-supported-target - -#include -int main(int argc, char **argv) { - char x[10]; - memset(x, 0, 10); - int res = x[argc * 10]; // BOOOM - // CHECK: {{READ of size 1 at 0x.* thread T0}} - // CHECK: {{ #0 0x.* in _?main .*zero-base-shadow.cc:}}[[@LINE-2]] - // CHECK: {{Address 0x.* is .* frame}} - // CHECK: main - - // Check that shadow for stack memory occupies lower part of address space. - // CHECK-64: =>0x0f - // CHECK-32: =>0x1 - return res; -} diff --git a/lib/asan/lit_tests/SharedLibs/darwin-dummy-shared-lib-so.cc b/lib/asan/lit_tests/SharedLibs/darwin-dummy-shared-lib-so.cc deleted file mode 100644 index 5d939991476e..000000000000 --- a/lib/asan/lit_tests/SharedLibs/darwin-dummy-shared-lib-so.cc +++ /dev/null @@ -1,13 +0,0 @@ -//===----------- darwin-dummy-shared-lib-so.cc ------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file is a part of AddressSanitizer, an address sanity checker. -// -//===----------------------------------------------------------------------===// -void foo() {} diff --git a/lib/asan/lit_tests/SharedLibs/dlclose-test-so.cc b/lib/asan/lit_tests/SharedLibs/dlclose-test-so.cc deleted file mode 100644 index 73e00507358a..000000000000 --- a/lib/asan/lit_tests/SharedLibs/dlclose-test-so.cc +++ /dev/null @@ -1,33 +0,0 @@ -//===----------- dlclose-test-so.cc -----------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file is a part of AddressSanitizer, an address sanity checker. -// -// Regression test for -// http://code.google.com/p/address-sanitizer/issues/detail?id=19 -//===----------------------------------------------------------------------===// -#include - -static int pad1; -static int static_var; -static int pad2; - -extern "C" -int *get_address_of_static_var() { - return &static_var; -} - -__attribute__((constructor)) -void at_dlopen() { - printf("%s: I am being dlopened\n", __FILE__); -} -__attribute__((destructor)) -void at_dlclose() { - printf("%s: I am being dlclosed\n", __FILE__); -} diff --git a/lib/asan/lit_tests/SharedLibs/init-order-dlopen-so.cc b/lib/asan/lit_tests/SharedLibs/init-order-dlopen-so.cc deleted file mode 100644 index 20ef2d8a00bb..000000000000 --- a/lib/asan/lit_tests/SharedLibs/init-order-dlopen-so.cc +++ /dev/null @@ -1,12 +0,0 @@ -#include -#include - -void inc_global(); - -int slow_init() { - sleep(1); - inc_global(); - return 42; -} - -int slowly_init_glob = slow_init(); diff --git a/lib/asan/lit_tests/SharedLibs/lit.local.cfg b/lib/asan/lit_tests/SharedLibs/lit.local.cfg deleted file mode 100644 index b3677c17a0f2..000000000000 --- a/lib/asan/lit_tests/SharedLibs/lit.local.cfg +++ /dev/null @@ -1,4 +0,0 @@ -# Sources in this directory are compiled as shared libraries and used by -# tests in parent directory. - -config.suffixes = [] diff --git a/lib/asan/lit_tests/SharedLibs/shared-lib-test-so.cc b/lib/asan/lit_tests/SharedLibs/shared-lib-test-so.cc deleted file mode 100644 index 686a24578082..000000000000 --- a/lib/asan/lit_tests/SharedLibs/shared-lib-test-so.cc +++ /dev/null @@ -1,21 +0,0 @@ -//===----------- shared-lib-test-so.cc --------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file is a part of AddressSanitizer, an address sanity checker. -// -//===----------------------------------------------------------------------===// -#include - -int pad[10]; -int GLOB[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - -extern "C" -void inc(int index) { - GLOB[index]++; -} diff --git a/lib/asan/lit_tests/TestCases/Darwin/interface_symbols_darwin.c b/lib/asan/lit_tests/TestCases/Darwin/interface_symbols_darwin.c new file mode 100644 index 000000000000..b453b64cafd2 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Darwin/interface_symbols_darwin.c @@ -0,0 +1,41 @@ +// Check the presense of interface symbols in the ASan runtime dylib. +// If you're changing this file, please also change +// ../Linux/interface_symbols.c + +// RUN: %clang_asan -dead_strip -O2 %s -o %t.exe +// RUN: rm -f %t.symbols %t.interface + +// RUN: nm -g `otool -L %t.exe | grep "asan_osx_dynamic.dylib" | \ +// RUN: tr -d '\011' | \ +// RUN: sed "s/.dylib.*/.dylib/"` \ +// RUN: | grep " T " | sed "s/.* T //" \ +// RUN: | grep "__asan_" | sed "s/___asan_/__asan_/" \ +// RUN: | grep -v "__asan_malloc_hook" \ +// RUN: | grep -v "__asan_free_hook" \ +// RUN: | grep -v "__asan_symbolize" \ +// RUN: | grep -v "__asan_default_options" \ +// RUN: | grep -v "__asan_on_error" > %t.symbols + +// RUN: cat %p/../../../asan_interface_internal.h \ +// RUN: | sed "s/\/\/.*//" | sed "s/typedef.*//" \ +// RUN: | grep -v "OPTIONAL" \ +// RUN: | grep "__asan_.*(" | sed "s/.* __asan_/__asan_/;s/(.*//" \ +// RUN: > %t.interface +// RUN: echo __asan_report_load1 >> %t.interface +// RUN: echo __asan_report_load2 >> %t.interface +// RUN: echo __asan_report_load4 >> %t.interface +// RUN: echo __asan_report_load8 >> %t.interface +// RUN: echo __asan_report_load16 >> %t.interface +// RUN: echo __asan_report_store1 >> %t.interface +// RUN: echo __asan_report_store2 >> %t.interface +// RUN: echo __asan_report_store4 >> %t.interface +// RUN: echo __asan_report_store8 >> %t.interface +// RUN: echo __asan_report_store16 >> %t.interface +// RUN: echo __asan_report_load_n >> %t.interface +// RUN: echo __asan_report_store_n >> %t.interface +// RUN: for i in `jot - 0 10`; do echo __asan_stack_malloc_$i >> %t.interface; done +// RUN: for i in `jot - 0 10`; do echo __asan_stack_free_$i >> %t.interface; done + +// RUN: cat %t.interface | sort -u | diff %t.symbols - + +int main() { return 0; } diff --git a/lib/asan/lit_tests/TestCases/Darwin/lit.local.cfg b/lib/asan/lit_tests/TestCases/Darwin/lit.local.cfg new file mode 100644 index 000000000000..a85dfcd24c08 --- /dev/null +++ b/lib/asan/lit_tests/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/lib/asan/lit_tests/TestCases/Darwin/malloc_set_zone_name-mprotect.cc b/lib/asan/lit_tests/TestCases/Darwin/malloc_set_zone_name-mprotect.cc new file mode 100644 index 000000000000..807a8283e788 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Darwin/malloc_set_zone_name-mprotect.cc @@ -0,0 +1,51 @@ +// Regression test for a bug in malloc_create_zone() +// (https://code.google.com/p/address-sanitizer/issues/detail?id=203) +// The old implementation of malloc_create_zone() didn't always return a +// page-aligned address, so we can only test on a best-effort basis. + +// RUN: %clangxx_asan %s -o %t +// RUN: %t 2>&1 + +#include +#include +#include +#include + +const int kNumIter = 4096; +const int kNumZones = 100; +int main() { + char *mem[kNumIter * 2]; + // Allocate memory chunks from different size classes up to 1 page. + // (For the case malloc() returns memory chunks in descending order) + for (int i = 0; i < kNumIter; i++) { + mem[i] = (char*)malloc(8 * i); + } + // Try to allocate a page-aligned malloc zone. Otherwise the mprotect() call + // in malloc_set_zone_name() will silently fail. + malloc_zone_t *zone = NULL; + bool aligned = false; + for (int i = 0; i < kNumZones; i++) { + zone = malloc_create_zone(0, 0); + if (((uintptr_t)zone & (~0xfff)) == (uintptr_t)zone) { + aligned = true; + break; + } + } + if (!aligned) { + printf("Warning: couldn't allocate a page-aligned zone."); + return 0; + } + // malloc_set_zone_name() calls mprotect(zone, 4096, PROT_READ | PROT_WRITE), + // modifies the zone contents and then calls mprotect(zone, 4096, PROT_READ). + malloc_set_zone_name(zone, "foobar"); + // Allocate memory chunks from different size classes again. + for (int i = 0; i < kNumIter; i++) { + mem[i + kNumIter] = (char*)malloc(8 * i); + } + // Access the allocated memory chunks and free them. + for (int i = 0; i < kNumIter * 2; i++) { + memset(mem[i], 'a', 8 * (i % kNumIter)); + free(mem[i]); + } + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/Darwin/malloc_zone-protected.cc b/lib/asan/lit_tests/TestCases/Darwin/malloc_zone-protected.cc new file mode 100644 index 000000000000..d5f6c7c12e67 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Darwin/malloc_zone-protected.cc @@ -0,0 +1,20 @@ +// Make sure the zones created by malloc_create_zone() are write-protected. +#include +#include + +// RUN: %clangxx_asan %s -o %t +// RUN: not %t 2>&1 | FileCheck %s + + +void *pwn(malloc_zone_t *unused_zone, size_t unused_size) { + printf("PWNED\n"); + return NULL; +} + +int main() { + malloc_zone_t *zone = malloc_create_zone(0, 0); + zone->malloc = pwn; + void *v = malloc_zone_malloc(zone, 1); + // CHECK-NOT: PWNED + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/Darwin/reexec-insert-libraries-env.cc b/lib/asan/lit_tests/TestCases/Darwin/reexec-insert-libraries-env.cc new file mode 100644 index 000000000000..208fe43ac7e4 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Darwin/reexec-insert-libraries-env.cc @@ -0,0 +1,20 @@ +// Make sure ASan doesn't hang in an exec loop if DYLD_INSERT_LIBRARIES is set. +// This is a regression test for +// https://code.google.com/p/address-sanitizer/issues/detail?id=159 + +// RUN: %clangxx_asan %s -o %t +// RUN: %clangxx %p/../SharedLibs/darwin-dummy-shared-lib-so.cc \ +// RUN: -dynamiclib -o darwin-dummy-shared-lib-so.dylib + +// FIXME: the following command line may hang in the case of a regression. +// RUN: DYLD_INSERT_LIBRARIES=darwin-dummy-shared-lib-so.dylib \ +// RUN: %t 2>&1 | FileCheck %s || exit 1 +#include +#include + +int main() { + const char kEnvName[] = "DYLD_INSERT_LIBRARIES"; + printf("%s=%s\n", kEnvName, getenv(kEnvName)); + // CHECK: {{DYLD_INSERT_LIBRARIES=.*darwin-dummy-shared-lib-so.dylib.*}} + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/Darwin/unset-insert-libraries-on-exec.cc b/lib/asan/lit_tests/TestCases/Darwin/unset-insert-libraries-on-exec.cc new file mode 100644 index 000000000000..fa0dd4f9df88 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Darwin/unset-insert-libraries-on-exec.cc @@ -0,0 +1,20 @@ +// Make sure ASan removes the runtime library from DYLD_INSERT_LIBRARIES before +// executing other programs. + +// RUN: %clangxx_asan %s -o %t +// RUN: %clangxx %p/../Helpers/echo-env.cc -o %T/echo-env +// RUN: %clangxx %p/../SharedLibs/darwin-dummy-shared-lib-so.cc \ +// RUN: -dynamiclib -o %t-darwin-dummy-shared-lib-so.dylib + +// Make sure DYLD_INSERT_LIBRARIES doesn't contain the runtime library before +// execl(). + +// RUN: %t %T/echo-env >/dev/null 2>&1 +// RUN: DYLD_INSERT_LIBRARIES=%t-darwin-dummy-shared-lib-so.dylib \ +// RUN: %t %T/echo-env 2>&1 | FileCheck %s || exit 1 +#include +int main(int argc, char *argv[]) { + execl(argv[1], argv[1], "DYLD_INSERT_LIBRARIES", NULL); + // CHECK: {{DYLD_INSERT_LIBRARIES = .*darwin-dummy-shared-lib-so.dylib.*}} + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/Helpers/blacklist-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/blacklist-extra.cc new file mode 100644 index 000000000000..627115cdda2b --- /dev/null +++ b/lib/asan/lit_tests/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/lib/asan/lit_tests/TestCases/Helpers/echo-env.cc b/lib/asan/lit_tests/TestCases/Helpers/echo-env.cc new file mode 100644 index 000000000000..65e91c155c84 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Helpers/echo-env.cc @@ -0,0 +1,19 @@ +// Helper binary for +// lit_tests/TestCases/Darwin/unset-insert-libraries-on-exec.cc +// Prints the environment variable with the given name. +#include +#include + +int main(int argc, char *argv[]) { + if (argc != 2) { + printf("Usage: %s ENVNAME\n", argv[0]); + exit(1); + } + const char *value = getenv(argv[1]); + if (value) { + printf("%s = %s\n", argv[1], value); + } else { + printf("%s not set.\n", argv[1]); + } + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/Helpers/init-order-atexit-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/init-order-atexit-extra.cc new file mode 100644 index 000000000000..e4189d19d099 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Helpers/init-order-atexit-extra.cc @@ -0,0 +1,16 @@ +#include + +class C { + public: + C() { value = 42; } + ~C() { } + int value; +}; + +C c; + +void AccessC() { + printf("C value: %d\n", c.value); +} + +int main() { return 0; } diff --git a/lib/asan/lit_tests/TestCases/Helpers/init-order-pthread-create-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/init-order-pthread-create-extra.cc new file mode 100644 index 000000000000..d4606f0afb52 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Helpers/init-order-pthread-create-extra.cc @@ -0,0 +1,2 @@ +void *bar(void *input); +void *glob2 = bar((void*)0x2345); diff --git a/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra.cc new file mode 100644 index 000000000000..09aed2112d5e --- /dev/null +++ b/lib/asan/lit_tests/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/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra2.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra2.cc new file mode 100644 index 000000000000..69455a0a6fc9 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist-extra2.cc @@ -0,0 +1,4 @@ +int zero_init(); +int badSrcGlobal = zero_init(); +int readBadSrcGlobal() { return badSrcGlobal; } + diff --git a/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist.txt b/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist.txt new file mode 100644 index 000000000000..83294635622d --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Helpers/initialization-blacklist.txt @@ -0,0 +1,3 @@ +global:*badGlobal*=init +type:*badNamespace::BadClass*=init +src:*initialization-blacklist-extra2.cc=init diff --git a/lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra.cc new file mode 100644 index 000000000000..3c4cb411defa --- /dev/null +++ b/lib/asan/lit_tests/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/lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra2.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-bug-extra2.cc new file mode 100644 index 000000000000..a3d8f190e58b --- /dev/null +++ b/lib/asan/lit_tests/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/lib/asan/lit_tests/TestCases/Helpers/initialization-constexpr-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-constexpr-extra.cc new file mode 100644 index 000000000000..b32466a981b3 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Helpers/initialization-constexpr-extra.cc @@ -0,0 +1,3 @@ +// Constexpr: +int getCoolestInteger(); +static int coolest_integer = getCoolestInteger(); diff --git a/lib/asan/lit_tests/TestCases/Helpers/initialization-nobug-extra.cc b/lib/asan/lit_tests/TestCases/Helpers/initialization-nobug-extra.cc new file mode 100644 index 000000000000..886165affd76 --- /dev/null +++ b/lib/asan/lit_tests/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/lib/asan/lit_tests/TestCases/Helpers/lit.local.cfg b/lib/asan/lit_tests/TestCases/Helpers/lit.local.cfg new file mode 100644 index 000000000000..2fc4d99456b0 --- /dev/null +++ b/lib/asan/lit_tests/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/lib/asan/lit_tests/TestCases/Linux/asan_prelink_test.cc b/lib/asan/lit_tests/TestCases/Linux/asan_prelink_test.cc new file mode 100644 index 000000000000..0f158c1bb3dd --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Linux/asan_prelink_test.cc @@ -0,0 +1,28 @@ +// Test if asan works with prelink. +// It does not actually use prelink, but relies on ld's flag -Ttext-segment +// or gold's flag -Ttext (we try the first flag first, if that fails we +// try the second flag). +// +// RUN: %clangxx_asan -c %s -o %t.o +// RUN: %clangxx_asan -DBUILD_SO=1 -fPIC -shared %s -o %t.so -Wl,-Ttext-segment=0x3600000000 ||\ +// RUN: %clangxx_asan -DBUILD_SO=1 -fPIC -shared %s -o %t.so -Wl,-Ttext=0x3600000000 +// RUN: %clangxx_asan %t.o %t.so -Wl,-R. -o %t +// RUN: ASAN_OPTIONS=verbosity=1 %t 2>&1 | FileCheck %s + +// REQUIRES: x86_64-supported-target, asan-64-bits +#if BUILD_SO +int G; +int *getG() { + return &G; +} +#else +#include +extern int *getG(); +int main(int argc, char **argv) { + long p = (long)getG(); + printf("SO mapped at %lx\n", p & ~0xffffffffUL); + *getG() = 0; +} +#endif +// CHECK: 0x003000000000, 0x004fffffffff{{.*}} MidMem +// CHECK: SO mapped at 3600000000 diff --git a/lib/asan/lit_tests/TestCases/Linux/clone_test.cc b/lib/asan/lit_tests/TestCases/Linux/clone_test.cc new file mode 100644 index 000000000000..0e12f35b400a --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Linux/clone_test.cc @@ -0,0 +1,44 @@ +// Regression test for: +// http://code.google.com/p/address-sanitizer/issues/detail?id=37 + +// RUN: %clangxx_asan -O0 %s -o %t && %t | FileCheck %s +// RUN: %clangxx_asan -O1 %s -o %t && %t | FileCheck %s +// RUN: %clangxx_asan -O2 %s -o %t && %t | FileCheck %s +// RUN: %clangxx_asan -O3 %s -o %t && %t | FileCheck %s + +#include +#include +#include +#include +#include +#include + +int Child(void *arg) { + char x[32] = {0}; // Stack gets poisoned. + printf("Child: %p\n", x); + _exit(1); // NoReturn, stack will remain unpoisoned unless we do something. +} + +int main(int argc, char **argv) { + const int kStackSize = 1 << 20; + char child_stack[kStackSize + 1]; + char *sp = child_stack + kStackSize; // Stack grows down. + printf("Parent: %p\n", sp); + pid_t clone_pid = clone(Child, sp, CLONE_FILES | CLONE_VM, NULL, 0, 0, 0); + int status; + pid_t wait_result = waitpid(clone_pid, &status, __WCLONE); + if (wait_result < 0) { + perror("waitpid"); + return 0; + } + if (wait_result == clone_pid && WIFEXITED(status)) { + // Make sure the child stack was indeed unpoisoned. + for (int i = 0; i < kStackSize; i++) + child_stack[i] = i; + int ret = child_stack[argc - 1]; + printf("PASSED\n"); + // CHECK: PASSED + return ret; + } + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/Linux/coverage.cc b/lib/asan/lit_tests/TestCases/Linux/coverage.cc new file mode 100644 index 000000000000..4373e9b13c68 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Linux/coverage.cc @@ -0,0 +1,45 @@ +// RUN: %clangxx_asan -mllvm -asan-coverage=1 -DSHARED %s -shared -o %t.so -fPIC +// RUN: %clangxx_asan -mllvm -asan-coverage=1 %s -o %t -Wl,-R. %t.so +// RUN: export ASAN_OPTIONS=coverage=1:verbosity=1 +// RUN: %t 2>&1 | FileCheck %s --check-prefix=CHECK-main +// RUN: %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-foo +// RUN: %t bar 2>&1 | FileCheck %s --check-prefix=CHECK-bar +// RUN: %t foo bar 2>&1 | FileCheck %s --check-prefix=CHECK-foo-bar + +#include +#include +#include + +#ifdef SHARED +void bar() { printf("bar\n"); } +#else +__attribute__((noinline)) +void foo() { printf("foo\n"); } +extern void bar(); + +int main(int argc, char **argv) { + fprintf(stderr, "PID: %d\n", getpid()); + for (int i = 1; i < argc; i++) { + if (!strcmp(argv[i], "foo")) + foo(); + if (!strcmp(argv[i], "bar")) + bar(); + } +} +#endif + +// CHECK-main: PID: [[PID:[0-9]+]] +// CHECK-main: [[PID]].sancov: 1 PCs written +// CHECK-main-NOT: .so.[[PID]] +// +// CHECK-foo: PID: [[PID:[0-9]+]] +// CHECK-foo: [[PID]].sancov: 2 PCs written +// CHECK-foo-NOT: .so.[[PID]] +// +// CHECK-bar: PID: [[PID:[0-9]+]] +// CHECK-bar: [[PID]].sancov: 1 PCs written +// CHECK-bar: .so.[[PID]].sancov: 1 PCs written +// +// CHECK-foo-bar: PID: [[PID:[0-9]+]] +// CHECK-foo-bar: [[PID]].sancov: 2 PCs written +// CHECK-foo-bar: so.[[PID]].sancov: 1 PCs written diff --git a/lib/asan/lit_tests/TestCases/Linux/glob.cc b/lib/asan/lit_tests/TestCases/Linux/glob.cc new file mode 100644 index 000000000000..123768b099ed --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Linux/glob.cc @@ -0,0 +1,29 @@ +// RUN: %clangxx_asan -O0 %s -o %t && %t %p 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -o %t && %t %p 2>&1 | FileCheck %s + +#include +#include +#include +#include +#include +#include + + +int main(int argc, char *argv[]) { + std::string path = argv[1]; + std::string pattern = path + "/glob_test_root/*a"; + printf("pattern: %s\n", pattern.c_str()); + + glob_t globbuf; + int res = glob(pattern.c_str(), 0, 0, &globbuf); + + printf("%d %s\n", errno, strerror(errno)); + assert(res == 0); + assert(globbuf.gl_pathc == 2); + printf("%zu\n", strlen(globbuf.gl_pathv[0])); + printf("%zu\n", strlen(globbuf.gl_pathv[1])); + globfree(&globbuf); + printf("PASS\n"); + // CHECK: PASS + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/Linux/glob_test_root/aa b/lib/asan/lit_tests/TestCases/Linux/glob_test_root/aa new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ab b/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ab new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ba b/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ba new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/lib/asan/lit_tests/TestCases/Linux/heap-overflow-large.cc b/lib/asan/lit_tests/TestCases/Linux/heap-overflow-large.cc new file mode 100644 index 000000000000..67e9c3718d59 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Linux/heap-overflow-large.cc @@ -0,0 +1,23 @@ +// Regression test for +// https://code.google.com/p/address-sanitizer/issues/detail?id=183 + +// RUN: %clangxx_asan -O2 %s -o %t +// RUN: not %t 12 2>&1 | FileCheck %s +// RUN: not %t 100 2>&1 | FileCheck %s +// RUN: not %t 10000 2>&1 | FileCheck %s + +#include +#include + +int main(int argc, char *argv[]) { + int *x = new int[5]; + memset(x, 0, sizeof(x[0]) * 5); + int index = atoi(argv[1]); + int res = x[index]; + // CHECK: AddressSanitizer: {{(heap-buffer-overflow|SEGV)}} + // CHECK: #0 0x{{.*}} in main {{.*}}heap-overflow-large.cc:[[@LINE-2]] + // CHECK: AddressSanitizer can not {{(provide additional info|describe address in more detail \(wild memory access suspected\))}} + // CHECK: SUMMARY: AddressSanitizer: {{(heap-buffer-overflow|SEGV)}} + delete[] x; + return res; +} diff --git a/lib/asan/lit_tests/TestCases/Linux/heavy_uar_test.cc b/lib/asan/lit_tests/TestCases/Linux/heavy_uar_test.cc new file mode 100644 index 000000000000..27b179e83624 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Linux/heavy_uar_test.cc @@ -0,0 +1,54 @@ +// RUN: export ASAN_OPTIONS=detect_stack_use_after_return=1 +// RUN: %clangxx_asan -O0 %s -o %t && \ +// RUN: not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -o %t && \ +// RUN: not %t 2>&1 | FileCheck %s + +#include +#include +#include + +__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 +__attribute__((noinline)) +void RecuriveFunctionWithStackFrame(int depth) { + if (depth <= 0) return; + char x[kFrameSize]; + x[0] = depth; + pretend_to_do_something(x); + RecuriveFunctionWithStackFrame(depth - 1); +} + +int main(int argc, char **argv) { + int n_iter = argc >= 2 ? atoi(argv[1]) : 1000; + int depth = argc >= 3 ? atoi(argv[2]) : 500; + for (int i = 0; i < n_iter; i++) { + RecuriveFunctionWithStackFrame<10>(depth); + RecuriveFunctionWithStackFrame<100>(depth); + RecuriveFunctionWithStackFrame<500>(depth); + RecuriveFunctionWithStackFrame<1024>(depth); + RecuriveFunctionWithStackFrame<2000>(depth); + RecuriveFunctionWithStackFrame<5000>(depth); + RecuriveFunctionWithStackFrame<10000>(depth); + } + char *stale_stack = LeakStack(); + RecuriveFunctionWithStackFrame<1024>(10); + stale_stack[100]++; + // CHECK: ERROR: AddressSanitizer: stack-use-after-return on address + // CHECK: is located in stack of thread T0 at offset 132 in frame + // CHECK: in LeakStack(){{.*}}heavy_uar_test.cc: + // CHECK: [32, 1056) 'x' + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/Linux/initialization-bug-any-order.cc b/lib/asan/lit_tests/TestCases/Linux/initialization-bug-any-order.cc new file mode 100644 index 000000000000..042a07e428d9 --- /dev/null +++ b/lib/asan/lit_tests/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 %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O0 %p/../Helpers/initialization-bug-extra.cc %s -o %t +// RUN: ASAN_OPTIONS=strict_init_order=true not %t 2>&1 | FileCheck %s + +// Do not test with optimization -- the error may be optimized away. + +#include + +// 'y' is a dynamically initialized global residing in a different TU. This +// dynamic initializer will read the value of 'y' before main starts. The +// result is undefined behavior, which should be caught by initialization order +// checking. +extern int y; +int __attribute__((noinline)) initX() { + return y + 1; + // CHECK: {{AddressSanitizer: initialization-order-fiasco}} + // CHECK: {{READ of size .* at 0x.* thread T0}} + // CHECK: {{#0 0x.* in .*initX.* .*initialization-bug-any-order.cc:}}[[@LINE-3]] + // CHECK: {{0x.* is located 0 bytes inside of global variable .*y.*}} +} + +// This initializer begins our initialization order problems. +static int x = initX(); + +int main() { + // ASan should have caused an exit before main runs. + printf("PASS\n"); + // CHECK-NOT: PASS + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/Linux/interception_failure_test.cc b/lib/asan/lit_tests/TestCases/Linux/interception_failure_test.cc new file mode 100644 index 000000000000..9d161aa2dccb --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Linux/interception_failure_test.cc @@ -0,0 +1,22 @@ +// If user provides his own libc functions, ASan doesn't +// intercept these functions. + +// RUN: %clangxx_asan -O0 %s -o %t && %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %s -o %t && %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -o %t && %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -o %t && %t 2>&1 | FileCheck %s +#include +#include + +extern "C" long strtol(const char *nptr, char **endptr, int base) { + fprintf(stderr, "my_strtol_interceptor\n"); + return 0; +} + +int main() { + char *x = (char*)malloc(10 * sizeof(char)); + free(x); + return (int)strtol(x, 0, 10); + // CHECK: my_strtol_interceptor + // CHECK-NOT: heap-use-after-free +} diff --git a/lib/asan/lit_tests/TestCases/Linux/interception_malloc_test.cc b/lib/asan/lit_tests/TestCases/Linux/interception_malloc_test.cc new file mode 100644 index 000000000000..cdd7239ab7bc --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Linux/interception_malloc_test.cc @@ -0,0 +1,23 @@ +// ASan interceptor can be accessed with __interceptor_ prefix. + +// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s +#include +#include +#include + +extern "C" void *__interceptor_malloc(size_t size); +extern "C" void *malloc(size_t size) { + write(2, "malloc call\n", sizeof("malloc call\n") - 1); + return __interceptor_malloc(size); +} + +int main() { + char *x = (char*)malloc(10 * sizeof(char)); + free(x); + return (int)strtol(x, 0, 10); + // CHECK: malloc call + // CHECK: heap-use-after-free +} diff --git a/lib/asan/lit_tests/TestCases/Linux/interception_readdir_r_test.cc b/lib/asan/lit_tests/TestCases/Linux/interception_readdir_r_test.cc new file mode 100644 index 000000000000..198e1f3884dd --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Linux/interception_readdir_r_test.cc @@ -0,0 +1,59 @@ +// RUN: %clangxx_asan -O0 %s -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %s -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s +// +// RUN: %clangxx_asan -O0 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s + +#include +#include +#include +#include +#include + + +int main() { + // Ensure the readdir_r interceptor doesn't erroneously mark the entire dirent + // as written when the end of the directory pointer is reached. + fputs("test1: reading the " TEMP_DIR " directory...\n", stderr); + DIR *d = opendir(TEMP_DIR); + struct dirent *result = (struct dirent *)(0xfeedbeef); + // We assume the temp dir for this test doesn't have crazy long file names. + char entry_buffer[4096]; + memset(entry_buffer, 0xab, sizeof(entry_buffer)); + unsigned count = 0; + do { + // Stamp the entry struct to try to trick the interceptor. + ((struct dirent *)entry_buffer)->d_reclen = 9999; + if (readdir_r(d, (struct dirent *)entry_buffer, &result) != 0) + abort(); + ++count; + } while (result != NULL); + fprintf(stderr, "read %d entries\n", count); + closedir(d); + // CHECK: test1: reading the {{.*}} directory... + // CHECK-NOT: stack-buffer-overflow + // CHECK: read {{.*}} entries + + // Ensure the readdir64_r interceptor doesn't have the bug either. + fputs("test2: reading the " TEMP_DIR " directory...\n", stderr); + d = opendir(TEMP_DIR); + struct dirent64 *result64; + memset(entry_buffer, 0xab, sizeof(entry_buffer)); + count = 0; + do { + // Stamp the entry struct to try to trick the interceptor. + ((struct dirent64 *)entry_buffer)->d_reclen = 9999; + if (readdir64_r(d, (struct dirent64 *)entry_buffer, &result64) != 0) + abort(); + ++count; + } while (result64 != NULL); + fprintf(stderr, "read %d entries\n", count); + closedir(d); + // CHECK: test2: reading the {{.*}} directory... + // CHECK-NOT: stack-buffer-overflow + // CHECK: read {{.*}} entries +} diff --git a/lib/asan/lit_tests/TestCases/Linux/interception_test.cc b/lib/asan/lit_tests/TestCases/Linux/interception_test.cc new file mode 100644 index 000000000000..2b3316d7dc8a --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Linux/interception_test.cc @@ -0,0 +1,22 @@ +// ASan interceptor can be accessed with __interceptor_ prefix. + +// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s +#include +#include + +extern "C" long __interceptor_strtol(const char *nptr, char **endptr, int base); +extern "C" long strtol(const char *nptr, char **endptr, int base) { + fprintf(stderr, "my_strtol_interceptor\n"); + return __interceptor_strtol(nptr, endptr, base); +} + +int main() { + char *x = (char*)malloc(10 * sizeof(char)); + free(x); + return (int)strtol(x, 0, 10); + // CHECK: my_strtol_interceptor + // CHECK: heap-use-after-free +} diff --git a/lib/asan/lit_tests/TestCases/Linux/interface_symbols_linux.c b/lib/asan/lit_tests/TestCases/Linux/interface_symbols_linux.c new file mode 100644 index 000000000000..d6ceda7af8b6 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Linux/interface_symbols_linux.c @@ -0,0 +1,35 @@ +// Check the presense of interface symbols in compiled file. + +// RUN: %clang_asan -O2 %s -o %t.exe +// RUN: nm -D %t.exe | grep " T " | sed "s/.* T //" \ +// RUN: | grep "__asan_" | sed "s/___asan_/__asan_/" \ +// RUN: | grep -v "__asan_malloc_hook" \ +// RUN: | grep -v "__asan_free_hook" \ +// RUN: | grep -v "__asan_symbolize" \ +// RUN: | grep -v "__asan_default_options" \ +// RUN: | grep -v "__asan_stack_" \ +// RUN: | grep -v "__asan_on_error" > %t.symbols +// RUN: cat %p/../../../asan_interface_internal.h \ +// RUN: | sed "s/\/\/.*//" | sed "s/typedef.*//" \ +// RUN: | grep -v "OPTIONAL" \ +// RUN: | grep "__asan_.*(" | sed "s/.* __asan_/__asan_/;s/(.*//" \ +// RUN: > %t.interface +// RUN: echo __asan_report_load1 >> %t.interface +// RUN: echo __asan_report_load2 >> %t.interface +// RUN: echo __asan_report_load4 >> %t.interface +// RUN: echo __asan_report_load8 >> %t.interface +// RUN: echo __asan_report_load16 >> %t.interface +// RUN: echo __asan_report_store1 >> %t.interface +// RUN: echo __asan_report_store2 >> %t.interface +// RUN: echo __asan_report_store4 >> %t.interface +// RUN: echo __asan_report_store8 >> %t.interface +// RUN: echo __asan_report_store16 >> %t.interface +// RUN: echo __asan_report_load_n >> %t.interface +// RUN: echo __asan_report_store_n >> %t.interface +// RUN: cat %t.interface | sort -u | diff %t.symbols - + +// FIXME: nm -D on powerpc somewhy shows ASan interface symbols residing +// in "initialized data section". +// REQUIRES: x86_64-supported-target,i386-supported-target + +int main() { return 0; } diff --git a/lib/asan/lit_tests/TestCases/Linux/lit.local.cfg b/lib/asan/lit_tests/TestCases/Linux/lit.local.cfg new file mode 100644 index 000000000000..57271b8078a4 --- /dev/null +++ b/lib/asan/lit_tests/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/lib/asan/lit_tests/TestCases/Linux/malloc-in-qsort.cc b/lib/asan/lit_tests/TestCases/Linux/malloc-in-qsort.cc new file mode 100644 index 000000000000..3251b35e143c --- /dev/null +++ b/lib/asan/lit_tests/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 %t 2>&1 | FileCheck %s --check-prefix=CHECK-FAST +// RUN: ASAN_OPTIONS=fast_unwind_on_malloc=0 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-SLOW + +// Test how well we unwind in presence of qsort in the stack +// (i.e. if we can unwind through a function compiled w/o frame pointers). +// https://code.google.com/p/address-sanitizer/issues/detail?id=137 + +// Fast unwinder is only avaliable on x86_64 and i386. +// REQUIRES: x86_64-supported-target + +// REQUIRES: compiler-rt-optimized + +#include +#include + +int *GlobalPtr; + +extern "C" { +int QsortCallback(const void *a, const void *b) { + char *x = (char*)a; + char *y = (char*)b; + printf("Calling QsortCallback\n"); + GlobalPtr = new int[10]; + return (int)*x - (int)*y; +} + +__attribute__((noinline)) +void MyQsort(char *a, size_t size) { + printf("Calling qsort\n"); + qsort(a, size, sizeof(char), QsortCallback); + printf("Done\n"); // Avoid tail call. +} +} // extern "C" + +int main() { + char a[2] = {1, 2}; + MyQsort(a, 2); + return GlobalPtr[10]; +} + +// Fast unwind: can not unwind through qsort. +// FIXME: this test does not properly work with slow unwind yet. + +// CHECK-FAST: ERROR: AddressSanitizer: heap-buffer-overflow +// CHECK-FAST: is located 0 bytes to the right +// CHECK-FAST: #0{{.*}}operator new +// CHECK-FAST-NEXT: #1{{.*}}QsortCallback +// CHECK-FAST-NOT: MyQsort +// +// CHECK-SLOW: ERROR: AddressSanitizer: heap-buffer-overflow +// CHECK-SLOW: is located 0 bytes to the right +// CHECK-SLOW: #0{{.*}}operator new +// CHECK-SLOW-NEXT: #1{{.*}}QsortCallback +// CHECK-SLOW: #{{.*}}MyQsort +// CHECK-SLOW-NEXT: #{{.*}}main diff --git a/lib/asan/lit_tests/TestCases/Linux/malloc_delete_mismatch.cc b/lib/asan/lit_tests/TestCases/Linux/malloc_delete_mismatch.cc new file mode 100644 index 000000000000..7010eb2de2e7 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Linux/malloc_delete_mismatch.cc @@ -0,0 +1,31 @@ +// Check that we detect malloc/delete mismatch only if the approptiate flag +// is set. + +// RUN: %clangxx_asan -g %s -o %t 2>&1 + +// Find error and provide malloc context. +// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=1 not %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=ALLOC-STACK + +// No error here. +// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=0 %t + +// Also works if no malloc context is available. +// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=1:malloc_context_size=0:fast_unwind_on_malloc=0 not %t 2>&1 | FileCheck %s +// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=1:malloc_context_size=0:fast_unwind_on_malloc=1 not %t 2>&1 | FileCheck %s +#include + +static volatile char *x; + +int main() { + x = (char*)malloc(10); + x[0] = 0; + delete x; +} +// CHECK: ERROR: AddressSanitizer: alloc-dealloc-mismatch (malloc vs operator delete) on 0x +// CHECK-NEXT: #0{{.*}}operator delete +// CHECK: #{{.*}}main +// CHECK: is located 0 bytes inside of 10-byte region +// CHECK-NEXT: allocated by thread T0 here: +// ALLOC-STACK-NEXT: #0{{.*}}malloc +// ALLOC-STACK: #{{.*}}main +// CHECK: HINT: {{.*}} you may set ASAN_OPTIONS=alloc_dealloc_mismatch=0 diff --git a/lib/asan/lit_tests/TestCases/Linux/overflow-in-qsort.cc b/lib/asan/lit_tests/TestCases/Linux/overflow-in-qsort.cc new file mode 100644 index 000000000000..139977261ec9 --- /dev/null +++ b/lib/asan/lit_tests/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 %t 2>&1 | FileCheck %s --check-prefix=CHECK-FAST +// RUN: ASAN_OPTIONS=fast_unwind_on_fatal=0 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-SLOW + +// Test how well we unwind in presence of qsort in the stack +// (i.e. if we can unwind through a function compiled w/o frame pointers). +// https://code.google.com/p/address-sanitizer/issues/detail?id=137 + +// Fast unwinder is only avaliable on x86_64 and i386. +// REQUIRES: x86_64-supported-target + +#include +#include + +int global_array[10]; +volatile int one = 1; + +extern "C" { +int QsortCallback(const void *a, const void *b) { + char *x = (char*)a; + char *y = (char*)b; + printf("Calling QsortCallback\n"); + global_array[one * 10] = 0; // BOOM + return (int)*x - (int)*y; +} + +__attribute__((noinline)) +void MyQsort(char *a, size_t size) { + printf("Calling qsort\n"); + qsort(a, size, sizeof(char), QsortCallback); + printf("Done\n"); // Avoid tail call. +} +} // extern "C" + +int main() { + char a[2] = {1, 2}; + MyQsort(a, 2); +} + +// Fast unwind: can not unwind through qsort. + +// CHECK-FAST: ERROR: AddressSanitizer: global-buffer-overflow +// CHECK-FAST: #0{{.*}} in QsortCallback +// CHECK-FAST-NOT: MyQsort +// CHECK-FAST: is located 0 bytes to the right of global variable 'global_array + +// CHECK-SLOW: ERROR: AddressSanitizer: global-buffer-overflow +// CHECK-SLOW: #0{{.*}} in QsortCallback +// CHECK-SLOW: #{{.*}} in MyQsort +// CHECK-SLOW: #{{.*}} in main +// CHECK-SLOW: is located 0 bytes to the right of global variable 'global_array diff --git a/lib/asan/lit_tests/TestCases/Linux/preinit_test.cc b/lib/asan/lit_tests/TestCases/Linux/preinit_test.cc new file mode 100644 index 000000000000..28e509472c0c --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Linux/preinit_test.cc @@ -0,0 +1,27 @@ +// RUN: %clangxx -DFUNC=zzzz %s -shared -o %t.so -fPIC +// RUN: %clangxx_asan -DFUNC=main %s -o %t -Wl,-R. %t.so +// RUN: %t + +// This test ensures that we call __asan_init early enough. +// We build a shared library w/o asan instrumentation +// and the binary with asan instrumentation. +// Both files include the same header (emulated by -DFUNC here) +// with C++ template magic which runs global initializer at library load time. +// The function get() is instrumented with asan, but called +// before the usual constructors are run. +// So, we must make sure that __asan_init is executed even earlier. +// +// See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56393 + +struct A { + int foo() const { return 0; } +}; +A get () { return A(); } +template struct O { + static A const e; +}; +template A const O ::e = get(); +int FUNC() { + return O::e.foo(); +} + diff --git a/lib/asan/lit_tests/TestCases/Linux/ptrace.cc b/lib/asan/lit_tests/TestCases/Linux/ptrace.cc new file mode 100644 index 000000000000..8831b81efa96 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Linux/ptrace.cc @@ -0,0 +1,52 @@ +// RUN: %clangxx_asan -O0 %s -o %t && %t +// RUN: %clangxx_asan -DPOSITIVE -O0 %s -o %t && not %t 2>&1 | FileCheck %s + +#include +#include +#include +#include +#include +#include +#include + +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 = ®s; +#ifdef POSITIVE + ++pregs; +#endif + res = ptrace(PTRACE_GETREGS, pid, NULL, pregs); + // CHECK: AddressSanitizer: stack-buffer-overflow + // CHECK: {{.*ptrace.cc:}}[[@LINE-2]] + assert(!res); +#if __WORDSIZE == 64 + printf("%zx\n", regs.rip); +#else + printf("%lx\n", regs.eip); +#endif + + user_fpregs_struct fpregs; + res = ptrace(PTRACE_GETFPREGS, pid, NULL, &fpregs); + assert(!res); + printf("%lx\n", (unsigned long)fpregs.cwd); + +#if __WORDSIZE == 32 + user_fpxregs_struct fpxregs; + res = ptrace(PTRACE_GETFPXREGS, pid, NULL, &fpxregs); + assert(!res); + printf("%lx\n", (unsigned long)fpxregs.mxcsr); +#endif + + ptrace(PTRACE_CONT, pid, NULL, NULL); + wait(NULL); + } + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/Linux/rlimit_mmap_test.cc b/lib/asan/lit_tests/TestCases/Linux/rlimit_mmap_test.cc new file mode 100644 index 000000000000..0d1d4baa7671 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Linux/rlimit_mmap_test.cc @@ -0,0 +1,16 @@ +// Check that we properly report mmap failure. +// RUN: %clangxx_asan %s -o %t && not %t 2>&1 | FileCheck %s +#include +#include +#include +#include + +static volatile void *x; + +int main(int argc, char **argv) { + struct rlimit mmap_resource_limit = { 0, 0 }; + assert(0 == setrlimit(RLIMIT_AS, &mmap_resource_limit)); + x = malloc(10000000); +// CHECK: ERROR: Failed to mmap + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/Linux/swapcontext_test.cc b/lib/asan/lit_tests/TestCases/Linux/swapcontext_test.cc new file mode 100644 index 000000000000..6cbb69a35321 --- /dev/null +++ b/lib/asan/lit_tests/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 && %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %s -o %t && %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -o %t && %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -o %t && %t 2>&1 | FileCheck %s +// +// This test is too sublte to try on non-x86 arch for now. +// REQUIRES: x86_64-supported-target,i386-supported-target + +#include +#include +#include + +ucontext_t orig_context; +ucontext_t child_context; + +const int kStackSize = 1 << 20; + +__attribute__((noinline)) +void Throw() { + throw 1; +} + +__attribute__((noinline)) +void ThrowAndCatch() { + try { + Throw(); + } catch(int a) { + printf("ThrowAndCatch: %d\n", a); + } +} + +void Child(int mode) { + char x[32] = {0}; // Stack gets poisoned. + printf("Child: %p\n", x); + ThrowAndCatch(); // Simulate __asan_handle_no_return(). + // (a) Do nothing, just return to parent function. + // (b) Jump into the original function. Stack remains poisoned unless we do + // something. + if (mode == 1) { + if (swapcontext(&child_context, &orig_context) < 0) { + perror("swapcontext"); + _exit(0); + } + } +} + +int Run(int arg, int mode, char *child_stack) { + printf("Child stack: %p\n", child_stack); + // Setup child context. + getcontext(&child_context); + child_context.uc_stack.ss_sp = child_stack; + child_context.uc_stack.ss_size = kStackSize / 2; + if (mode == 0) { + child_context.uc_link = &orig_context; + } + makecontext(&child_context, (void (*)())Child, 1, mode); + if (swapcontext(&orig_context, &child_context) < 0) { + perror("swapcontext"); + return 0; + } + // Touch childs's stack to make sure it's unpoisoned. + for (int i = 0; i < kStackSize; i++) { + child_stack[i] = i; + } + return child_stack[arg]; +} + +int main(int argc, char **argv) { + char stack[kStackSize + 1]; + // CHECK: WARNING: ASan doesn't fully support makecontext/swapcontext + int ret = 0; + ret += Run(argc - 1, 0, stack); + printf("Test1 passed\n"); + // CHECK: Test1 passed + ret += Run(argc - 1, 1, stack); + printf("Test2 passed\n"); + // CHECK: Test2 passed + char *heap = new char[kStackSize + 1]; + ret += Run(argc - 1, 0, heap); + printf("Test3 passed\n"); + // CHECK: Test3 passed + ret += Run(argc - 1, 1, heap); + printf("Test4 passed\n"); + // CHECK: Test4 passed + + delete [] heap; + return ret; +} diff --git a/lib/asan/lit_tests/TestCases/Linux/syscalls.cc b/lib/asan/lit_tests/TestCases/Linux/syscalls.cc new file mode 100644 index 000000000000..4bcbe446113e --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Linux/syscalls.cc @@ -0,0 +1,22 @@ +// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s + +#include +#include +#include +#include +#include + +#include + +/* Test the presence of __sanitizer_syscall_ in the tool runtime, and general + sanity of their behaviour. */ + +int main(int argc, char *argv[]) { + char buf[1000]; + __sanitizer_syscall_pre_recvmsg(0, buf - 1, 0); + // CHECK: AddressSanitizer: stack-buffer-{{.*}}erflow + // CHECK: READ of size {{.*}} at {{.*}} thread T0 + // CHECK: #0 {{.*}} in __sanitizer_syscall{{.*}}recvmsg + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/Linux/time_null_regtest.cc b/lib/asan/lit_tests/TestCases/Linux/time_null_regtest.cc new file mode 100644 index 000000000000..566409be6a19 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Linux/time_null_regtest.cc @@ -0,0 +1,20 @@ +// RUN: %clangxx_asan -O0 %s -fsanitize-address-zero-base-shadow -pie -o %t && %t 2>&1 | FileCheck %s + +// Zero-base shadow only works on x86_64 and i386. +// REQUIRES: x86_64-supported-target + +// A regression test for time(NULL), which caused ASan to crash in the +// zero-based shadow mode on Linux. +// FIXME: this test does not work on Darwin, because the code pages of the +// executable interleave with the zero-based shadow. + +#include +#include +#include + +int main() { + time_t t = time(NULL); + fprintf(stderr, "Time: %s\n", ctime(&t)); // NOLINT + // CHECK: {{Time: .* .* .*}} + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/Linux/tsd_dtor_leak.cc b/lib/asan/lit_tests/TestCases/Linux/tsd_dtor_leak.cc new file mode 100644 index 000000000000..a1d89ee437d4 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Linux/tsd_dtor_leak.cc @@ -0,0 +1,39 @@ +// Regression test for a leak in tsd: +// https://code.google.com/p/address-sanitizer/issues/detail?id=233 +// RUN: %clangxx_asan -O1 %s -o %t +// RUN: ASAN_OPTIONS=quarantine_size=1 %t +#include +#include +#include +#include + +extern "C" size_t __asan_get_heap_size(); +static pthread_key_t tsd_key; + +void *Thread(void *) { + pthread_setspecific(tsd_key, malloc(10)); + return 0; +} + +static volatile void *v; + +void Dtor(void *tsd) { + v = malloc(10000); + free(tsd); + free((void*)v); // The bug was that this was leaking. +} + +int main() { + assert(0 == pthread_key_create(&tsd_key, Dtor)); + size_t old_heap_size = 0; + for (int i = 0; i < 10; i++) { + pthread_t t; + pthread_create(&t, 0, Thread, 0); + pthread_join(t, 0); + size_t new_heap_size = __asan_get_heap_size(); + fprintf(stderr, "heap size: new: %zd old: %zd\n", new_heap_size, old_heap_size); + if (old_heap_size) + assert(old_heap_size == new_heap_size); + old_heap_size = new_heap_size; + } +} diff --git a/lib/asan/lit_tests/TestCases/Linux/uar_signals.cc b/lib/asan/lit_tests/TestCases/Linux/uar_signals.cc new file mode 100644 index 000000000000..9663859dfefd --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Linux/uar_signals.cc @@ -0,0 +1,70 @@ +// This test shows that the current implementation of use-after-return is +// not signal-safe. +// RUN: %clangxx_asan -O1 %s -o %t -lpthread && %t +// RUN: %clangxx_asan -O1 %s -o %t -lpthread && %t +#include +#include +#include +#include +#include + +int *g; +int n_signals; + +typedef void (*Sigaction)(int, siginfo_t *, void *); + +void SignalHandler(int, siginfo_t*, void*) { + int local; + g = &local; + n_signals++; + // printf("s: %p\n", &local); +} + +static void EnableSigprof(Sigaction SignalHandler) { + struct sigaction sa; + sa.sa_sigaction = SignalHandler; + sa.sa_flags = SA_RESTART | SA_SIGINFO; + sigemptyset(&sa.sa_mask); + if (sigaction(SIGPROF, &sa, NULL) != 0) { + perror("sigaction"); + abort(); + } + struct itimerval timer; + timer.it_interval.tv_sec = 0; + timer.it_interval.tv_usec = 1; + timer.it_value = timer.it_interval; + if (setitimer(ITIMER_PROF, &timer, 0) != 0) { + perror("setitimer"); + abort(); + } +} + +void RecursiveFunction(int depth) { + if (depth == 0) return; + int local; + g = &local; + // printf("r: %p\n", &local); + // printf("[%2d] n_signals: %d\n", depth, n_signals); + RecursiveFunction(depth - 1); + RecursiveFunction(depth - 1); +} + +void *Thread(void *) { + RecursiveFunction(18); + return NULL; +} + +int main(int argc, char **argv) { + EnableSigprof(SignalHandler); + + for (int i = 0; i < 4; i++) { + fprintf(stderr, "."); + const int kNumThread = sizeof(void*) == 8 ? 16 : 8; + pthread_t t[kNumThread]; + for (int i = 0; i < kNumThread; i++) + pthread_create(&t[i], 0, Thread, 0); + for (int i = 0; i < kNumThread; i++) + pthread_join(t[i], 0); + } + fprintf(stderr, "\n"); +} diff --git a/lib/asan/lit_tests/TestCases/Linux/unpoison_tls.cc b/lib/asan/lit_tests/TestCases/Linux/unpoison_tls.cc new file mode 100644 index 000000000000..d67c4f954e43 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Linux/unpoison_tls.cc @@ -0,0 +1,35 @@ +// Test that TLS is unpoisoned on thread death. +// REQUIRES: x86_64-supported-target,i386-supported-target + +// RUN: %clangxx_asan -O1 %s -o %t && %t 2>&1 + +#include +#include +#include + +#include + +__thread int64_t tls_var[2]; + +volatile int64_t *p_tls_var; + +void *first(void *arg) { + ASAN_POISON_MEMORY_REGION(&tls_var, sizeof(tls_var)); + p_tls_var = tls_var; + return 0; +} + +void *second(void *arg) { + assert(tls_var == p_tls_var); + *p_tls_var = 1; + return 0; +} + +int main(int argc, char *argv[]) { + pthread_t p; + assert(0 == pthread_create(&p, 0, first, 0)); + assert(0 == pthread_join(p, 0)); + assert(0 == pthread_create(&p, 0, second, 0)); + assert(0 == pthread_join(p, 0)); + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow32.cc b/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow32.cc new file mode 100644 index 000000000000..e6bcc5597471 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow32.cc @@ -0,0 +1,24 @@ +// RUN: %clangxx_asan -O0 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t +// RUN: not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t +// RUN: not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t +// RUN: not %t 2>&1 | FileCheck %s + +// Zero-base shadow only works on x86_64 and i386. +// REQUIRES: i386-supported-target, asan-32-bits + +#include +int main(int argc, char **argv) { + char x[10]; + memset(x, 0, 10); + int res = x[argc * 10]; // BOOOM + // CHECK: {{READ of size 1 at 0x.* thread T0}} + // CHECK: {{ #0 0x.* in main .*zero-base-shadow32.cc:}}[[@LINE-2]] + // CHECK: {{Address 0x.* is .* frame}} + // CHECK: main + + // Check that shadow for stack memory occupies lower part of address space. + // CHECK: =>0x1 + return res; +} diff --git a/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow64.cc b/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow64.cc new file mode 100644 index 000000000000..1db725c95752 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow64.cc @@ -0,0 +1,24 @@ +// RUN: %clangxx_asan -O0 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t +// RUN: not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t +// RUN: not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t +// RUN: not %t 2>&1 | FileCheck %s + +// Zero-base shadow only works on x86_64 and i386. +// REQUIRES: x86_64-supported-target, asan-64-bits + +#include +int main(int argc, char **argv) { + char x[10]; + memset(x, 0, 10); + int res = x[argc * 10]; // BOOOM + // CHECK: {{READ of size 1 at 0x.* thread T0}} + // CHECK: {{ #0 0x.* in main .*zero-base-shadow64.cc:}}[[@LINE-2]] + // CHECK: {{Address 0x.* is .* frame}} + // CHECK: main + + // Check that shadow for stack memory occupies lower part of address space. + // CHECK: =>0x0f + return res; +} diff --git a/lib/asan/lit_tests/TestCases/SharedLibs/darwin-dummy-shared-lib-so.cc b/lib/asan/lit_tests/TestCases/SharedLibs/darwin-dummy-shared-lib-so.cc new file mode 100644 index 000000000000..5d939991476e --- /dev/null +++ b/lib/asan/lit_tests/TestCases/SharedLibs/darwin-dummy-shared-lib-so.cc @@ -0,0 +1,13 @@ +//===----------- darwin-dummy-shared-lib-so.cc ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +//===----------------------------------------------------------------------===// +void foo() {} diff --git a/lib/asan/lit_tests/TestCases/SharedLibs/dlclose-test-so.cc b/lib/asan/lit_tests/TestCases/SharedLibs/dlclose-test-so.cc new file mode 100644 index 000000000000..73e00507358a --- /dev/null +++ b/lib/asan/lit_tests/TestCases/SharedLibs/dlclose-test-so.cc @@ -0,0 +1,33 @@ +//===----------- dlclose-test-so.cc -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// Regression test for +// http://code.google.com/p/address-sanitizer/issues/detail?id=19 +//===----------------------------------------------------------------------===// +#include + +static int pad1; +static int static_var; +static int pad2; + +extern "C" +int *get_address_of_static_var() { + return &static_var; +} + +__attribute__((constructor)) +void at_dlopen() { + printf("%s: I am being dlopened\n", __FILE__); +} +__attribute__((destructor)) +void at_dlclose() { + printf("%s: I am being dlclosed\n", __FILE__); +} diff --git a/lib/asan/lit_tests/TestCases/SharedLibs/init-order-dlopen-so.cc b/lib/asan/lit_tests/TestCases/SharedLibs/init-order-dlopen-so.cc new file mode 100644 index 000000000000..dc097a520d03 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/SharedLibs/init-order-dlopen-so.cc @@ -0,0 +1,12 @@ +#include +#include + +extern "C" void inc_global(); + +int slow_init() { + sleep(1); + inc_global(); + return 42; +} + +int slowly_init_glob = slow_init(); diff --git a/lib/asan/lit_tests/TestCases/SharedLibs/lit.local.cfg b/lib/asan/lit_tests/TestCases/SharedLibs/lit.local.cfg new file mode 100644 index 000000000000..b3677c17a0f2 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/SharedLibs/lit.local.cfg @@ -0,0 +1,4 @@ +# Sources in this directory are compiled as shared libraries and used by +# tests in parent directory. + +config.suffixes = [] diff --git a/lib/asan/lit_tests/TestCases/SharedLibs/shared-lib-test-so.cc b/lib/asan/lit_tests/TestCases/SharedLibs/shared-lib-test-so.cc new file mode 100644 index 000000000000..6ef565ce47b3 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/SharedLibs/shared-lib-test-so.cc @@ -0,0 +1,26 @@ +//===----------- shared-lib-test-so.cc --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +//===----------------------------------------------------------------------===// +#include + +int pad[10]; +int GLOB[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +extern "C" +void inc(int index) { + GLOB[index]++; +} + +extern "C" +void inc2(int *a, int index) { + a[index]++; +} diff --git a/lib/asan/lit_tests/TestCases/allocator_returns_null.cc b/lib/asan/lit_tests/TestCases/allocator_returns_null.cc new file mode 100644 index 000000000000..595c9e252f86 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/allocator_returns_null.cc @@ -0,0 +1,81 @@ +// Test the behavior of malloc/calloc/realloc when the allocation size is huge. +// By default (allocator_may_return_null=0) the process should crash. +// With allocator_may_return_null=1 the allocator should return 0. +// +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: not %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH +// RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH +// RUN: ASAN_OPTIONS=allocator_may_return_null=1 %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mNULL +// RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cCRASH +// RUN: ASAN_OPTIONS=allocator_may_return_null=1 %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cNULL +// RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coCRASH +// RUN: ASAN_OPTIONS=allocator_may_return_null=1 %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coNULL +// RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rCRASH +// RUN: ASAN_OPTIONS=allocator_may_return_null=1 %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rNULL +// RUN: ASAN_OPTIONS=allocator_may_return_null=0 not %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrCRASH +// RUN: ASAN_OPTIONS=allocator_may_return_null=1 %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrNULL + +#include +#include +#include +#include +#include +#include +int main(int argc, char **argv) { + volatile size_t size = std::numeric_limits::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::max(); + size_t kArraySize = 4096; + volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10; + x = (char*)calloc(kArraySize, kArraySize2); + } + + if (!strcmp(argv[1], "realloc")) { + fprintf(stderr, "realloc:\n"); + x = (char*)realloc(0, size); + } + if (!strcmp(argv[1], "realloc-after-malloc")) { + fprintf(stderr, "realloc-after-malloc:\n"); + char *t = (char*)malloc(100); + *t = 42; + x = (char*)realloc(t, size); + assert(*t == 42); + } + // The NULL pointer is printed differently on different systems, while (long)0 + // is always the same. + fprintf(stderr, "x: %lx\n", (long)x); + return x != 0; +} +// CHECK-mCRASH: malloc: +// CHECK-mCRASH: AddressSanitizer's allocator is terminating the process +// CHECK-cCRASH: calloc: +// CHECK-cCRASH: AddressSanitizer's allocator is terminating the process +// CHECK-coCRASH: calloc-overflow: +// CHECK-coCRASH: AddressSanitizer's allocator is terminating the process +// CHECK-rCRASH: realloc: +// CHECK-rCRASH: AddressSanitizer's allocator is terminating the process +// CHECK-mrCRASH: realloc-after-malloc: +// CHECK-mrCRASH: AddressSanitizer's allocator is terminating the process + +// CHECK-mNULL: malloc: +// CHECK-mNULL: x: 0 +// CHECK-cNULL: calloc: +// CHECK-cNULL: x: 0 +// CHECK-coNULL: calloc-overflow: +// CHECK-coNULL: x: 0 +// CHECK-rNULL: realloc: +// CHECK-rNULL: x: 0 +// CHECK-mrNULL: realloc-after-malloc: +// CHECK-mrNULL: x: 0 diff --git a/lib/asan/lit_tests/TestCases/allow_user_segv.cc b/lib/asan/lit_tests/TestCases/allow_user_segv.cc new file mode 100644 index 000000000000..55cf6044e7a0 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/allow_user_segv.cc @@ -0,0 +1,48 @@ +// Regression test for +// https://code.google.com/p/address-sanitizer/issues/detail?id=180 + +// RUN: %clangxx_asan -O0 %s -o %t && ASAN_OPTIONS=allow_user_segv_handler=true not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -o %t && ASAN_OPTIONS=allow_user_segv_handler=true not %t 2>&1 | FileCheck %s + +#include +#include + +struct sigaction user_sigaction; +struct sigaction original_sigaction; + +void User_OnSIGSEGV(int signum, siginfo_t *siginfo, void *context) { + fprintf(stderr, "User sigaction called\n"); + if (original_sigaction.sa_flags | SA_SIGINFO) + original_sigaction.sa_sigaction(signum, siginfo, context); + else + original_sigaction.sa_handler(signum); +} + +int DoSEGV() { + volatile int *x = 0; + return *x; +} + +int main() { + user_sigaction.sa_sigaction = User_OnSIGSEGV; + user_sigaction.sa_flags = SA_SIGINFO; +#if defined(__APPLE__) && !defined(__LP64__) + // On 32-bit Darwin KERN_PROTECTION_FAILURE (SIGBUS) is delivered. + int signum = SIGBUS; +#else + // On 64-bit Darwin KERN_INVALID_ADDRESS (SIGSEGV) is delivered. + // On Linux SIGSEGV is delivered as well. + int signum = SIGSEGV; +#endif + if (sigaction(signum, &user_sigaction, &original_sigaction)) { + perror("sigaction"); + return 1; + } + fprintf(stderr, "User sigaction installed\n"); + return DoSEGV(); +} + +// CHECK: User sigaction installed +// CHECK-NEXT: User sigaction called +// CHECK-NEXT: ASAN:SIGSEGV +// CHECK: AddressSanitizer: SEGV on unknown address diff --git a/lib/asan/lit_tests/TestCases/asan-symbolize-sanity-test.cc b/lib/asan/lit_tests/TestCases/asan-symbolize-sanity-test.cc new file mode 100644 index 000000000000..0efe245bb6b5 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/asan-symbolize-sanity-test.cc @@ -0,0 +1,39 @@ +// Check that asan_symbolize.py script works (for binaries, ASan RTL and +// shared object files. + +// RUN: %clangxx_asan -O0 %p/SharedLibs/shared-lib-test-so.cc -fPIC -shared -o %t-so.so +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: ASAN_SYMBOLIZER_PATH= not %t 2>&1 | %asan_symbolize | FileCheck %s +#include +#include +#include + +#include + +using std::string; + +typedef void (fun_t)(int*, int); + +int main(int argc, char *argv[]) { + string path = string(argv[0]) + "-so.so"; + printf("opening %s ... \n", path.c_str()); + void *lib = dlopen(path.c_str(), RTLD_NOW); + if (!lib) { + printf("error in dlopen(): %s\n", dlerror()); + return 1; + } + fun_t *inc2 = (fun_t*)dlsym(lib, "inc2"); + if (!inc2) return 1; + printf("ok\n"); + int *array = (int*)malloc(40); + inc2(array, 1); + inc2(array, -1); // BOOM + // CHECK: ERROR: AddressSanitizer: heap-buffer-overflow + // CHECK: READ of size 4 at 0x{{.*}} + // CHECK: #0 {{.*}} in inc2 {{.*}}shared-lib-test-so.cc:25 + // CHECK: #1 {{.*}} in main {{.*}}asan-symbolize-sanity-test.cc:[[@LINE-4]] + // CHECK: allocated by thread T{{.*}} here: + // CHECK: #{{.*}} in {{(wrap_|__interceptor_)?}}malloc + // CHECK: #{{.*}} in main {{.*}}asan-symbolize-sanity-test.cc:[[@LINE-9]] + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/assign_large_valloc_to_global.cc b/lib/asan/lit_tests/TestCases/assign_large_valloc_to_global.cc new file mode 100644 index 000000000000..b0a501576945 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/assign_large_valloc_to_global.cc @@ -0,0 +1,8 @@ +// Make sure we don't report a leak nor hang. +// RUN: %clangxx_asan -O3 %s -o %t && %t +#include +#ifndef __APPLE__ +#include +#endif // __APPLE__ +int *p = (int*)valloc(1 << 20); +int main() { } diff --git a/lib/asan/lit_tests/TestCases/atexit_stats.cc b/lib/asan/lit_tests/TestCases/atexit_stats.cc new file mode 100644 index 000000000000..e3b1269d25cc --- /dev/null +++ b/lib/asan/lit_tests/TestCases/atexit_stats.cc @@ -0,0 +1,13 @@ +// Make sure we report atexit stats. +// RUN: %clangxx_asan -O3 %s -o %t +// RUN: ASAN_OPTIONS=atexit=1:print_stats=1 %t 2>&1 | FileCheck %s +#include +#if !defined(__APPLE__) +#include +#endif +int *p1 = (int*)malloc(900); +int *p2 = (int*)malloc(90000); +int *p3 = (int*)malloc(9000000); +int main() { } + +// CHECK: AddressSanitizer exit stats: diff --git a/lib/asan/lit_tests/TestCases/blacklist.cc b/lib/asan/lit_tests/TestCases/blacklist.cc new file mode 100644 index 000000000000..46625ee7bdb5 --- /dev/null +++ b/lib/asan/lit_tests/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 && %t 2>&1 +// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -O1 %s -o %t \ +// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1 +// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -O2 %s -o %t \ +// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1 +// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -O3 %s -o %t \ +// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1 + +// badGlobal is accessed improperly, but we blacklisted it. Align +// it to make sure memory past the end of badGlobal will be in +// the same page. +__attribute__((aligned(16))) int badGlobal; +int readBadGlobal() { + return (&badGlobal)[1]; +} + +// A function which is broken, but excluded in the blacklist. +int brokenFunction(int argc) { + char x[10] = {0}; + return x[argc * 10]; // BOOM +} + +// This function is defined in Helpers/blacklist-extra.cc, a source file which +// is blacklisted by name +int externalBrokenFunction(int x); + +int main(int argc, char **argv) { + brokenFunction(argc); + int x = readBadGlobal(); + externalBrokenFunction(argc); + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/contiguous_container.cc b/lib/asan/lit_tests/TestCases/contiguous_container.cc new file mode 100644 index 000000000000..aa97592c7bb9 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/contiguous_container.cc @@ -0,0 +1,47 @@ +// RUN: %clangxx_asan -O %s -o %t && %t +// +// Test __sanitizer_annotate_contiguous_container. + +#include +#include +#include +#include + +extern "C" { +void __sanitizer_annotate_contiguous_container(void *beg, void *end, + void *old_mid, void *new_mid); +bool __asan_address_is_poisoned(void *addr); +} // extern "C" + +void TestContainer(size_t capacity) { + char *beg = new char[capacity]; + char *end = beg + capacity; + char *mid = beg + capacity; + char *old_mid = 0; + unsigned seed = 0; + + for (int i = 0; i < 10000; i++) { + size_t size = rand_r(&seed) % (capacity + 1); + assert(size <= capacity); + old_mid = mid; + mid = beg + size; + __sanitizer_annotate_contiguous_container(beg, end, old_mid, mid); + + for (size_t idx = 0; idx < size; idx++) + assert(!__asan_address_is_poisoned(beg + idx)); + for (size_t idx = size; idx < capacity; idx++) + assert(__asan_address_is_poisoned(beg + idx)); + } + + // Don't forget to unpoison the whole thing before destroing/reallocating. + __sanitizer_annotate_contiguous_container(beg, end, mid, end); + for (size_t idx = 0; idx < capacity; idx++) + assert(!__asan_address_is_poisoned(beg + idx)); + delete[] beg; +} + +int main(int argc, char **argv) { + int n = argc == 1 ? 128 : atoi(argv[1]); + for (int i = 0; i <= n; i++) + TestContainer(i); +} diff --git a/lib/asan/lit_tests/TestCases/current_allocated_bytes.cc b/lib/asan/lit_tests/TestCases/current_allocated_bytes.cc new file mode 100644 index 000000000000..669cf150bdfb --- /dev/null +++ b/lib/asan/lit_tests/TestCases/current_allocated_bytes.cc @@ -0,0 +1,43 @@ +// RUN: %clangxx_asan -O0 %s -o %t && %t +// RUN: %clangxx_asan -O2 %s -o %t && %t + +#include +#include +#include +#include +#include + +const size_t kLargeAlloc = 1UL << 20; + +void* allocate(void *arg) { + volatile void *ptr = malloc(kLargeAlloc); + free((void*)ptr); + return 0; +} + +void* check_stats(void *arg) { + assert(__asan_get_current_allocated_bytes() > 0); + return 0; +} + +int main() { + size_t used_mem = __asan_get_current_allocated_bytes(); + printf("Before: %zu\n", used_mem); + const int kNumIterations = 1000; + for (int iter = 0; iter < kNumIterations; iter++) { + pthread_t thr[4]; + for (int j = 0; j < 4; j++) { + assert(0 == + pthread_create(&thr[j], 0, (j < 2) ? allocate : check_stats, 0)); + } + for (int j = 0; j < 4; j++) + assert(0 == pthread_join(thr[j], 0)); + used_mem = __asan_get_current_allocated_bytes(); + if (used_mem > kLargeAlloc) { + printf("After iteration %d: %zu\n", iter, used_mem); + return 1; + } + } + printf("Success after %d iterations\n", kNumIterations); + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/deep_call_stack.cc b/lib/asan/lit_tests/TestCases/deep_call_stack.cc new file mode 100644 index 000000000000..e24704b9019e --- /dev/null +++ b/lib/asan/lit_tests/TestCases/deep_call_stack.cc @@ -0,0 +1,25 @@ +// Check that UAR mode can handle very deep recusrion. +// export ASAN_OPTIONS=detect_stack_use_after_return=1 +// RUN: %clangxx_asan -O2 %s -o %t && \ +// RUN: %t 2>&1 | FileCheck %s +// Also check that use_sigaltstack+verbosity doesn't crash. +// RUN: ASAN_OPTIONS=verbosity=1:use_sigaltstack=1 %t | FileCheck %s +#include + +__attribute__((noinline)) +void RecursiveFunc(int depth, int *ptr) { + if ((depth % 1000) == 0) + printf("[%05d] ptr: %p\n", depth, ptr); + if (depth == 0) + return; + int local; + RecursiveFunc(depth - 1, &local); +} + +int main(int argc, char **argv) { + RecursiveFunc(40000, 0); + return 0; +} +// CHECK: [40000] ptr: +// CHECK: [20000] ptr: +// CHECK: [00000] ptr diff --git a/lib/asan/lit_tests/TestCases/deep_stack_uaf.cc b/lib/asan/lit_tests/TestCases/deep_stack_uaf.cc new file mode 100644 index 000000000000..920411c4ac52 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/deep_stack_uaf.cc @@ -0,0 +1,31 @@ +// Check that we can store lots of stack frames if asked to. + +// RUN: %clangxx_asan -O0 %s -o %t 2>&1 +// RUN: ASAN_OPTIONS=malloc_context_size=120:redzone=512 not %t 2>&1 | FileCheck %s +#include +#include + +template +struct DeepFree { + static void free(char *x) { + DeepFree::free(x); + } +}; + +template<> +struct DeepFree<0> { + static void free(char *x) { + ::free(x); + } +}; + +int main() { + char *x = (char*)malloc(10); + // deep_free(x); + DeepFree<200>::free(x); + return x[5]; + // CHECK: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}} + // CHECK: DeepFree<36> + // CHECK: DeepFree<98> + // CHECK: DeepFree<115> +} diff --git a/lib/asan/lit_tests/TestCases/deep_tail_call.cc b/lib/asan/lit_tests/TestCases/deep_tail_call.cc new file mode 100644 index 000000000000..2e7aa8e0208f --- /dev/null +++ b/lib/asan/lit_tests/TestCases/deep_tail_call.cc @@ -0,0 +1,20 @@ +// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s + +// CHECK: AddressSanitizer: global-buffer-overflow +int global[10]; +// CHECK: {{#0.*call4}} +void __attribute__((noinline)) call4(int i) { global[i+10]++; } +// CHECK: {{#1.*call3}} +void __attribute__((noinline)) call3(int i) { call4(i); } +// CHECK: {{#2.*call2}} +void __attribute__((noinline)) call2(int i) { call3(i); } +// CHECK: {{#3.*call1}} +void __attribute__((noinline)) call1(int i) { call2(i); } +// CHECK: {{#4.*main}} +int main(int argc, char **argv) { + call1(argc); + return global[0]; +} diff --git a/lib/asan/lit_tests/TestCases/deep_thread_stack.cc b/lib/asan/lit_tests/TestCases/deep_thread_stack.cc new file mode 100644 index 000000000000..92e0d66c82eb --- /dev/null +++ b/lib/asan/lit_tests/TestCases/deep_thread_stack.cc @@ -0,0 +1,57 @@ +// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s + +#include + +int *x; + +void *AllocThread(void *arg) { + x = new int; + *x = 42; + return NULL; +} + +void *FreeThread(void *arg) { + delete x; + return NULL; +} + +void *AccessThread(void *arg) { + *x = 43; // BOOM + return NULL; +} + +typedef void* (*callback_type)(void* arg); + +void *RunnerThread(void *function) { + pthread_t thread; + pthread_create(&thread, NULL, (callback_type)function, NULL); + pthread_join(thread, NULL); + return NULL; +} + +void RunThread(callback_type function) { + pthread_t runner; + pthread_create(&runner, NULL, RunnerThread, (void*)function); + pthread_join(runner, NULL); +} + +int main(int argc, char *argv[]) { + RunThread(AllocThread); + RunThread(FreeThread); + RunThread(AccessThread); + return (x != 0); +} + +// CHECK: AddressSanitizer: heap-use-after-free +// CHECK: WRITE of size 4 at 0x{{.*}} thread T[[ACCESS_THREAD:[0-9]+]] +// CHECK: freed by thread T[[FREE_THREAD:[0-9]+]] here: +// CHECK: previously allocated by thread T[[ALLOC_THREAD:[0-9]+]] here: +// CHECK: Thread T[[ACCESS_THREAD]] created by T[[ACCESS_RUNNER:[0-9]+]] here: +// CHECK: Thread T[[ACCESS_RUNNER]] created by T0 here: +// CHECK: Thread T[[FREE_THREAD]] created by T[[FREE_RUNNER:[0-9]+]] here: +// CHECK: Thread T[[FREE_RUNNER]] created by T0 here: +// CHECK: Thread T[[ALLOC_THREAD]] created by T[[ALLOC_RUNNER:[0-9]+]] here: +// CHECK: Thread T[[ALLOC_RUNNER]] created by T0 here: diff --git a/lib/asan/lit_tests/TestCases/default_blacklist.cc b/lib/asan/lit_tests/TestCases/default_blacklist.cc new file mode 100644 index 000000000000..25a1ae1752b0 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/default_blacklist.cc @@ -0,0 +1,3 @@ +// Test that ASan uses the default blacklist from resource directory. +// RUN: %clangxx_asan -### %s 2>&1 | FileCheck %s +// CHECK: fsanitize-blacklist={{.*}}asan_blacklist.txt diff --git a/lib/asan/lit_tests/TestCases/default_options.cc b/lib/asan/lit_tests/TestCases/default_options.cc new file mode 100644 index 000000000000..84b80557b852 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/default_options.cc @@ -0,0 +1,15 @@ +// RUN: %clangxx_asan -O2 %s -o %t +// RUN: %t 2>&1 | FileCheck %s + +const char *kAsanDefaultOptions="verbosity=1 foo=bar"; + +extern "C" +__attribute__((no_sanitize_address)) +const char *__asan_default_options() { + // CHECK: Using the defaults from __asan_default_options: {{.*}} foo=bar + return kAsanDefaultOptions; +} + +int main() { + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/dlclose-test.cc b/lib/asan/lit_tests/TestCases/dlclose-test.cc new file mode 100644 index 000000000000..03ed16016116 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/dlclose-test.cc @@ -0,0 +1,81 @@ +// Regression test for +// http://code.google.com/p/address-sanitizer/issues/detail?id=19 +// Bug description: +// 1. application dlopens foo.so +// 2. asan registers all globals from foo.so +// 3. application dlcloses foo.so +// 4. application mmaps some memory to the location where foo.so was before +// 5. application starts using this mmaped memory, but asan still thinks there +// are globals. +// 6. BOOM + +// This sublte test assumes that after a foo.so is dlclose-d +// we can mmap the region of memory that has been occupied by the library. +// It works on i368/x86_64 Linux, but not necessary anywhere else. +// REQUIRES: x86_64-supported-target,i386-supported-target + +// RUN: %clangxx_asan -O0 %p/SharedLibs/dlclose-test-so.cc \ +// RUN: -fPIC -shared -o %t-so.so +// RUN: %clangxx_asan -O0 %s -o %t && %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %p/SharedLibs/dlclose-test-so.cc \ +// RUN: -fPIC -shared -o %t-so.so +// RUN: %clangxx_asan -O1 %s -o %t && %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %p/SharedLibs/dlclose-test-so.cc \ +// RUN: -fPIC -shared -o %t-so.so +// RUN: %clangxx_asan -O2 %s -o %t && %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %p/SharedLibs/dlclose-test-so.cc \ +// RUN: -fPIC -shared -o %t-so.so +// RUN: %clangxx_asan -O3 %s -o %t && %t 2>&1 | FileCheck %s + +#include +#include +#include +#include +#include +#include + +#include + +using std::string; + +typedef int *(fun_t)(); + +int main(int argc, char *argv[]) { + string path = string(argv[0]) + "-so.so"; + size_t PageSize = sysconf(_SC_PAGESIZE); + printf("opening %s ... \n", path.c_str()); + void *lib = dlopen(path.c_str(), RTLD_NOW); + if (!lib) { + printf("error in dlopen(): %s\n", dlerror()); + return 1; + } + fun_t *get = (fun_t*)dlsym(lib, "get_address_of_static_var"); + if (!get) { + printf("failed dlsym\n"); + return 1; + } + int *addr = get(); + assert(((size_t)addr % 32) == 0); // should be 32-byte aligned. + printf("addr: %p\n", addr); + addr[0] = 1; // make sure we can write there. + + // Now dlclose the shared library. + printf("attempting to dlclose\n"); + if (dlclose(lib)) { + printf("failed to dlclose\n"); + return 1; + } + // Now, the page where 'addr' is unmapped. Map it. + size_t page_beg = ((size_t)addr) & ~(PageSize - 1); + void *res = mmap((void*)(page_beg), PageSize, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 0, 0); + if (res == (char*)-1L) { + printf("failed to mmap\n"); + return 1; + } + addr[1] = 2; // BOOM (if the bug is not fixed). + printf("PASS\n"); + // CHECK: PASS + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/double-free.cc b/lib/asan/lit_tests/TestCases/double-free.cc new file mode 100644 index 000000000000..6bfd4fa2c7e5 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/double-free.cc @@ -0,0 +1,25 @@ +// RUN: %clangxx_asan -O0 %s -o %t 2>&1 +// RUN: not %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=MALLOC-CTX + +// Also works if no malloc context is available. +// RUN: ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=0 not %t 2>&1 | FileCheck %s +// RUN: ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=1 not %t 2>&1 | FileCheck %s + +#include +#include +int main(int argc, char **argv) { + char *x = (char*)malloc(10 * sizeof(char)); + memset(x, 0, 10); + int res = x[argc]; + free(x); + free(x + argc - 1); // BOOM + // CHECK: AddressSanitizer: attempting double-free{{.*}}in thread T0 + // CHECK: #0 0x{{.*}} in {{.*}}free + // CHECK: #1 0x{{.*}} in main {{.*}}double-free.cc:[[@LINE-3]] + // CHECK: freed by thread T0 here: + // MALLOC-CTX: #0 0x{{.*}} in {{.*}}free + // MALLOC-CTX: #1 0x{{.*}} in main {{.*}}double-free.cc:[[@LINE-7]] + // CHECK: allocated by thread T0 here: + // MALLOC-CTX: double-free.cc:[[@LINE-12]] + return res; +} diff --git a/lib/asan/lit_tests/TestCases/force_inline_opt0.cc b/lib/asan/lit_tests/TestCases/force_inline_opt0.cc new file mode 100644 index 000000000000..775a66dfe2fe --- /dev/null +++ b/lib/asan/lit_tests/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 && %t +// RUN: %clangxx_asan -O0 %s -o %t && %t +__attribute__((always_inline)) +void foo(int *x) { + *x = 0; +} + +int main() { + int x; + foo(&x); + return x; +} diff --git a/lib/asan/lit_tests/TestCases/free_hook_realloc.cc b/lib/asan/lit_tests/TestCases/free_hook_realloc.cc new file mode 100644 index 000000000000..7a71964b0032 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/free_hook_realloc.cc @@ -0,0 +1,32 @@ +// Check that free hook doesn't conflict with Realloc. +// RUN: %clangxx_asan -O2 %s -o %t +// RUN: %t 2>&1 | FileCheck %s +#include +#include + +static void *glob_ptr; + +extern "C" { +void __asan_free_hook(void *ptr) { + if (ptr == glob_ptr) { + *(int*)ptr = 0; + write(1, "FreeHook\n", sizeof("FreeHook\n")); + } +} +} + +int main() { + int *x = (int*)malloc(100); + x[0] = 42; + glob_ptr = x; + int *y = (int*)realloc(x, 200); + // Verify that free hook was called and didn't spoil the memory. + if (y[0] != 42) { + _exit(1); + } + write(1, "Passed\n", sizeof("Passed\n")); + free(y); + // CHECK: FreeHook + // CHECK: Passed + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/global-demangle.cc b/lib/asan/lit_tests/TestCases/global-demangle.cc new file mode 100644 index 000000000000..d050b70f0fca --- /dev/null +++ b/lib/asan/lit_tests/TestCases/global-demangle.cc @@ -0,0 +1,17 @@ +// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s + +namespace XXX { +class YYY { + public: + static char ZZZ[]; +}; +char YYY::ZZZ[] = "abc"; +} + +int main(int argc, char **argv) { + return (int)XXX::YYY::ZZZ[argc + 5]; // BOOM + // CHECK: {{READ of size 1 at 0x.*}} + // CHECK: {{0x.* is located 2 bytes to the right of global variable}} + // CHECK: 'XXX::YYY::ZZZ' {{.*}} of size 4 + // CHECK: 'XXX::YYY::ZZZ' is ascii string 'abc' +} diff --git a/lib/asan/lit_tests/TestCases/global-overflow.cc b/lib/asan/lit_tests/TestCases/global-overflow.cc new file mode 100644 index 000000000000..0f080f55f2f1 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/global-overflow.cc @@ -0,0 +1,21 @@ +// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s + +#include +int main(int argc, char **argv) { + static char XXX[10]; + static char YYY[10]; + static char ZZZ[10]; + memset(XXX, 0, 10); + memset(YYY, 0, 10); + memset(ZZZ, 0, 10); + int res = YYY[argc * 10]; // BOOOM + // CHECK: {{READ of size 1 at 0x.* thread T0}} + // CHECK: {{ #0 0x.* in main .*global-overflow.cc:}}[[@LINE-2]] + // CHECK: {{0x.* is located 0 bytes to the right of global variable}} + // CHECK: {{.*YYY.* of size 10}} + res += XXX[argc] + ZZZ[argc]; + return res; +} diff --git a/lib/asan/lit_tests/TestCases/heap-overflow.cc b/lib/asan/lit_tests/TestCases/heap-overflow.cc new file mode 100644 index 000000000000..2c943a36014f --- /dev/null +++ b/lib/asan/lit_tests/TestCases/heap-overflow.cc @@ -0,0 +1,24 @@ +// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK +// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK +// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK +// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK + +#include +#include +int main(int argc, char **argv) { + char *x = (char*)malloc(10 * sizeof(char)); + memset(x, 0, 10); + int res = x[argc * 10]; // BOOOM + // CHECK: {{READ of size 1 at 0x.* thread T0}} + // CHECK: {{ #0 0x.* in main .*heap-overflow.cc:}}[[@LINE-2]] + // CHECK: {{0x.* is located 0 bytes to the right of 10-byte region}} + // CHECK: {{allocated by thread T0 here:}} + + // CHECK-Linux: {{ #0 0x.* in .*malloc}} + // CHECK-Linux: {{ #1 0x.* in main .*heap-overflow.cc:9}} + + // CHECK-Darwin: {{ #0 0x.* in wrap_malloc.*}} + // CHECK-Darwin: {{ #1 0x.* in main .*heap-overflow.cc:9}} + free(x); + return res; +} diff --git a/lib/asan/lit_tests/TestCases/huge_negative_hea_oob.cc b/lib/asan/lit_tests/TestCases/huge_negative_hea_oob.cc new file mode 100644 index 000000000000..58a44c5fb68e --- /dev/null +++ b/lib/asan/lit_tests/TestCases/huge_negative_hea_oob.cc @@ -0,0 +1,13 @@ +// RUN: %clangxx_asan %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O %s -o %t && not %t 2>&1 | FileCheck %s +// Check that we can find huge buffer overflows to the left. +#include +#include +int main(int argc, char **argv) { + char *x = (char*)malloc(1 << 20); + memset(x, 0, 10); + int res = x[-argc * 4000]; // BOOOM + // CHECK: is located 4000 bytes to the left of + free(x); + return res; +} diff --git a/lib/asan/lit_tests/TestCases/init-order-atexit.cc b/lib/asan/lit_tests/TestCases/init-order-atexit.cc new file mode 100644 index 000000000000..e38cdd273d58 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/init-order-atexit.cc @@ -0,0 +1,31 @@ +// Test for the following situation: +// (1) global A is constructed. +// (2) exit() is called during construction of global B. +// (3) destructor of A reads uninitialized global C from another module. +// We do *not* want to report init-order bug in this case. + +// RUN: %clangxx_asan -O0 %s %p/Helpers/init-order-atexit-extra.cc -o %t +// RUN: ASAN_OPTIONS=strict_init_order=true not %t 2>&1 | FileCheck %s + +#include +#include + +void AccessC(); + +class A { + public: + A() { } + ~A() { AccessC(); printf("PASSED\n"); } + // CHECK-NOT: AddressSanitizer + // CHECK: PASSED +}; + +A a; + +class B { + public: + B() { exit(1); } + ~B() { } +}; + +B b; diff --git a/lib/asan/lit_tests/TestCases/init-order-dlopen.cc b/lib/asan/lit_tests/TestCases/init-order-dlopen.cc new file mode 100644 index 000000000000..d30d11999246 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/init-order-dlopen.cc @@ -0,0 +1,57 @@ +// Regression test for +// https://code.google.com/p/address-sanitizer/issues/detail?id=178 + +// Assume we're on Darwin and try to pass -U to the linker. If this flag is +// unsupported, don't use it. +// RUN: %clangxx_asan -O0 %p/SharedLibs/init-order-dlopen-so.cc \ +// RUN: -fPIC -shared -o %t-so.so -Wl,-U,_inc_global || \ +// RUN: %clangxx_asan -O0 %p/SharedLibs/init-order-dlopen-so.cc \ +// RUN: -fPIC -shared -o %t-so.so +// If the linker doesn't support --export-dynamic (which is ELF-specific), +// try to link without that option. +// FIXME: find a better solution. +// RUN: %clangxx_asan -O0 %s -o %t -Wl,--export-dynamic || \ +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: ASAN_OPTIONS=strict_init_order=true %t 2>&1 | FileCheck %s +#include +#include +#include +#include + +#include + +using std::string; + +int foo() { + return 42; +} +int global = foo(); + +__attribute__((visibility("default"))) +extern "C" +void inc_global() { + global++; +} + +void *global_poller(void *arg) { + while (true) { + if (global != 42) + break; + usleep(100); + } + return 0; +} + +int main(int argc, char *argv[]) { + pthread_t p; + pthread_create(&p, 0, global_poller, 0); + string path = string(argv[0]) + "-so.so"; + if (0 == dlopen(path.c_str(), RTLD_NOW)) { + fprintf(stderr, "dlerror: %s\n", dlerror()); + return 1; + } + pthread_join(p, 0); + printf("PASSED\n"); + // CHECK: PASSED + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/init-order-pthread-create.cc b/lib/asan/lit_tests/TestCases/init-order-pthread-create.cc new file mode 100644 index 000000000000..52031216d5bb --- /dev/null +++ b/lib/asan/lit_tests/TestCases/init-order-pthread-create.cc @@ -0,0 +1,32 @@ +// Check that init-order checking is properly disabled if pthread_create is +// called. + +// RUN: %clangxx_asan %s %p/Helpers/init-order-pthread-create-extra.cc -o %t +// RUN: ASAN_OPTIONS=strict_init_order=true %t + +#include +#include + +void *run(void *arg) { + return arg; +} + +void *foo(void *input) { + pthread_t t; + pthread_create(&t, 0, run, input); + void *res; + pthread_join(t, &res); + return res; +} + +void *bar(void *input) { + return input; +} + +void *glob = foo((void*)0x1234); +extern void *glob2; + +int main() { + printf("%p %p\n", glob, glob2); + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/initialization-blacklist.cc b/lib/asan/lit_tests/TestCases/initialization-blacklist.cc new file mode 100644 index 000000000000..f40fcc082f9a --- /dev/null +++ b/lib/asan/lit_tests/TestCases/initialization-blacklist.cc @@ -0,0 +1,32 @@ +// Test for blacklist functionality of initialization-order checker. + +// RUN: %clangxx_asan -O0 %s %p/Helpers/initialization-blacklist-extra.cc\ +// RUN: %p/Helpers/initialization-blacklist-extra2.cc \ +// RUN: -fsanitize-blacklist=%p/Helpers/initialization-blacklist.txt \ +// RUN: -fsanitize=init-order -o %t +// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 +// RUN: %clangxx_asan -O1 %s %p/Helpers/initialization-blacklist-extra.cc\ +// RUN: %p/Helpers/initialization-blacklist-extra2.cc \ +// RUN: -fsanitize-blacklist=%p/Helpers/initialization-blacklist.txt \ +// RUN: -fsanitize=init-order -o %t +// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 +// RUN: %clangxx_asan -O2 %s %p/Helpers/initialization-blacklist-extra.cc\ +// RUN: %p/Helpers/initialization-blacklist-extra2.cc \ +// RUN: -fsanitize-blacklist=%p/Helpers/initialization-blacklist.txt \ +// RUN: -fsanitize=init-order -o %t +// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 + +// Function is defined in another TU. +int readBadGlobal(); +int x = readBadGlobal(); // init-order bug. + +// Function is defined in another TU. +int accessBadObject(); +int y = accessBadObject(); // init-order bug. + +int readBadSrcGlobal(); +int z = readBadSrcGlobal(); // init-order bug. + +int main(int argc, char **argv) { + return argc + x + y + z - 1; +} diff --git a/lib/asan/lit_tests/TestCases/initialization-bug.cc b/lib/asan/lit_tests/TestCases/initialization-bug.cc new file mode 100644 index 000000000000..fb289b1c7ebe --- /dev/null +++ b/lib/asan/lit_tests/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: ASAN_OPTIONS=check_initialization_order=true not %t 2>&1 | FileCheck %s + +// Do not test with optimization -- the error may be optimized away. + +// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=186 +// XFAIL: darwin + +#include + +// The structure of the test is: +// "x", "y", "z" are dynamically initialized globals. +// Value of "x" depends on "y", value of "y" depends on "z". +// "x" and "z" are defined in this TU, "y" is defined in another one. +// Thus we shoud stably report initialization order fiasco independently of +// the translation unit order. + +int initZ() { + return 5; +} +int z = initZ(); + +// 'y' is a dynamically initialized global residing in a different TU. This +// dynamic initializer will read the value of 'y' before main starts. The +// result is undefined behavior, which should be caught by initialization order +// checking. +extern int y; +int __attribute__((noinline)) initX() { + return y + 1; + // CHECK: {{AddressSanitizer: initialization-order-fiasco}} + // CHECK: {{READ of size .* at 0x.* thread T0}} + // CHECK: {{0x.* is located 0 bytes inside of global variable .*(y|z).*}} +} + +// This initializer begins our initialization order problems. +static int x = initX(); + +int main() { + // ASan should have caused an exit before main runs. + printf("PASS\n"); + // CHECK-NOT: PASS + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/initialization-constexpr.cc b/lib/asan/lit_tests/TestCases/initialization-constexpr.cc new file mode 100644 index 000000000000..65c95edd5081 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/initialization-constexpr.cc @@ -0,0 +1,31 @@ +// Constexpr: +// We need to check that a global variable initialized with a constexpr +// constructor can be accessed during dynamic initialization (as a constexpr +// constructor implies that it was initialized during constant initialization, +// not dynamic initialization). + +// RUN: %clangxx_asan -O0 %s %p/Helpers/initialization-constexpr-extra.cc\ +// RUN: --std=c++11 -fsanitize=init-order -o %t +// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 +// RUN: %clangxx_asan -O1 %s %p/Helpers/initialization-constexpr-extra.cc\ +// RUN: --std=c++11 -fsanitize=init-order -o %t +// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 +// RUN: %clangxx_asan -O2 %s %p/Helpers/initialization-constexpr-extra.cc\ +// RUN: --std=c++11 -fsanitize=init-order -o %t +// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 +// RUN: %clangxx_asan -O3 %s %p/Helpers/initialization-constexpr-extra.cc\ +// RUN: --std=c++11 -fsanitize=init-order -o %t +// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 + +class Integer { + private: + int value; + + public: + constexpr Integer(int x = 0) : value(x) {} + int getValue() {return value;} +}; +Integer coolestInteger(42); +int getCoolestInteger() { return coolestInteger.getValue(); } + +int main() { return 0; } diff --git a/lib/asan/lit_tests/TestCases/initialization-nobug.cc b/lib/asan/lit_tests/TestCases/initialization-nobug.cc new file mode 100644 index 000000000000..ed37d137f8cb --- /dev/null +++ b/lib/asan/lit_tests/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 -fsanitize=init-order -o %t +// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 +// RUN: %clangxx_asan -O1 %s %p/Helpers/initialization-nobug-extra.cc -fsanitize=init-order -o %t +// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 +// RUN: %clangxx_asan -O2 %s %p/Helpers/initialization-nobug-extra.cc -fsanitize=init-order -o %t +// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 +// RUN: %clangxx_asan -O3 %s %p/Helpers/initialization-nobug-extra.cc -fsanitize=init-order -o %t +// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 + +// Simple access: +// Make sure that accessing a global in the same TU is safe + +bool condition = true; +int initializeSameTU() { + return condition ? 0x2a : 052; +} +int sameTU = initializeSameTU(); + +// Linker initialized: +// Check that access to linker initialized globals originating from a different +// TU's initializer is safe. + +int A = (1 << 1) + (1 << 3) + (1 << 5), B; +int getAB() { + return A * B; +} + +// Function local statics: +// Check that access to function local statics originating from a different +// TU's initializer is safe. + +int countCalls() { + static int calls; + return ++calls; +} + +// Trivial constructor, non-trivial destructor. +struct StructWithDtor { + ~StructWithDtor() { } + int value; +}; +StructWithDtor struct_with_dtor; +int getStructWithDtorValue() { return struct_with_dtor.value; } + +int main() { return 0; } diff --git a/lib/asan/lit_tests/TestCases/inline.cc b/lib/asan/lit_tests/TestCases/inline.cc new file mode 100644 index 000000000000..792aff59f4ba --- /dev/null +++ b/lib/asan/lit_tests/TestCases/inline.cc @@ -0,0 +1,19 @@ +// RUN: %clangxx_asan -O3 %s -o %t && %t + +// Test that no_sanitize_address attribute applies even when the function would +// be normally inlined. + +#include + +__attribute__((no_sanitize_address)) +int f(int *p) { + return *p; // BOOOM?? Nope! +} + +int main(int argc, char **argv) { + int * volatile x = (int*)malloc(2*sizeof(int) + 2); + int res = f(x + 2); + if (res) + exit(0); + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/interface_test.cc b/lib/asan/lit_tests/TestCases/interface_test.cc new file mode 100644 index 000000000000..297b5526e9d9 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/interface_test.cc @@ -0,0 +1,8 @@ +// Check that user may include ASan interface header. +// RUN: %clang_asan %s -o %t && %t +// RUN: %clang %s -o %t && %t +#include + +int main() { + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/invalid-free.cc b/lib/asan/lit_tests/TestCases/invalid-free.cc new file mode 100644 index 000000000000..f940b501279a --- /dev/null +++ b/lib/asan/lit_tests/TestCases/invalid-free.cc @@ -0,0 +1,21 @@ +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: not %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=MALLOC-CTX + +// Also works if no malloc context is available. +// RUN: ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=0 not %t 2>&1 | FileCheck %s +// RUN: ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=1 not %t 2>&1 | FileCheck %s + +#include +#include +int main(int argc, char **argv) { + char *x = (char*)malloc(10 * sizeof(char)); + memset(x, 0, 10); + int res = x[argc]; + free(x + 5); // BOOM + // CHECK: AddressSanitizer: attempting free on address{{.*}}in thread T0 + // CHECK: invalid-free.cc:[[@LINE-2]] + // CHECK: is located 5 bytes inside of 10-byte region + // CHECK: allocated by thread T0 here: + // MALLOC-CTX: invalid-free.cc:[[@LINE-8]] + return res; +} diff --git a/lib/asan/lit_tests/TestCases/ioctl.cc b/lib/asan/lit_tests/TestCases/ioctl.cc new file mode 100644 index 000000000000..08ca688d3872 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/ioctl.cc @@ -0,0 +1,24 @@ +// RUN: %clangxx_asan -O0 -g %s -o %t && ASAN_OPTIONS=handle_ioctl=1 not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 -g %s -o %t && ASAN_OPTIONS=handle_ioctl=1 not %t 2>&1 | FileCheck %s + +// RUN: %clangxx_asan -O0 -g %s -o %t && %t +// RUN: %clangxx_asan -O3 -g %s -o %t && %t + +#include +#include +#include +#include +#include + +int main(int argc, char **argv) { + int fd = socket(AF_INET, SOCK_DGRAM, 0); + + int nonblock; + int res = ioctl(fd, FIONBIO, &nonblock + 1); + // CHECK: AddressSanitizer: stack-buffer-overflow + // CHECK: READ of size 4 at + // CHECK: {{#.* in main .*ioctl.cc:}}[[@LINE-3]] + assert(res == 0); + close(fd); + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/large_func_test.cc b/lib/asan/lit_tests/TestCases/large_func_test.cc new file mode 100644 index 000000000000..0534bcd31142 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/large_func_test.cc @@ -0,0 +1,51 @@ +// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK +// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK +// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK +// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK + +#include +__attribute__((noinline)) +static void LargeFunction(int *x, int zero) { + x[0]++; + x[1]++; + x[2]++; + x[3]++; + x[4]++; + x[5]++; + x[6]++; + x[7]++; + x[8]++; + x[9]++; + + // CHECK: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}} + // CHECK: {{0x.* at pc 0x.* bp 0x.* sp 0x.*}} + // CHECK: {{READ of size 4 at 0x.* thread T0}} + x[zero + 103]++; // we should report this exact line + // atos incorrectly extracts the symbol name for the static functions on + // Darwin. + // CHECK-Linux: {{#0 0x.* in LargeFunction.*large_func_test.cc:}}[[@LINE-3]] + // CHECK-Darwin: {{#0 0x.* in .*LargeFunction.*large_func_test.cc}}:[[@LINE-4]] + + x[10]++; + x[11]++; + x[12]++; + x[13]++; + x[14]++; + x[15]++; + x[16]++; + x[17]++; + x[18]++; + x[19]++; +} + +int main(int argc, char **argv) { + int *x = new int[100]; + LargeFunction(x, argc - 1); + // CHECK: {{ #1 0x.* in main .*large_func_test.cc:}}[[@LINE-1]] + // CHECK: {{0x.* is located 12 bytes to the right of 400-byte region}} + // CHECK: {{allocated by thread T0 here:}} + // CHECK-Linux: {{ #0 0x.* in operator new.*}} + // CHECK-Darwin: {{ #0 0x.* in .*_Zna.*}} + // CHECK: {{ #1 0x.* in main .*large_func_test.cc:}}[[@LINE-7]] + delete x; +} diff --git a/lib/asan/lit_tests/TestCases/log-path_test.cc b/lib/asan/lit_tests/TestCases/log-path_test.cc new file mode 100644 index 000000000000..1072670fbff4 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/log-path_test.cc @@ -0,0 +1,39 @@ +// RUN: %clangxx_asan %s -o %t + +// Regular run. +// RUN: not %t 2> %t.out +// RUN: FileCheck %s --check-prefix=CHECK-ERROR < %t.out + +// Good log_path. +// RUN: rm -f %t.log.* +// RUN: ASAN_OPTIONS=log_path=%t.log not %t 2> %t.out +// RUN: FileCheck %s --check-prefix=CHECK-ERROR < %t.log.* + +// Invalid log_path. +// RUN: ASAN_OPTIONS=log_path=/INVALID not %t 2> %t.out +// RUN: FileCheck %s --check-prefix=CHECK-INVALID < %t.out + +// Too long log_path. +// RUN: ASAN_OPTIONS=log_path=`for((i=0;i<10000;i++)); do echo -n $i; done` \ +// RUN: not %t 2> %t.out +// RUN: FileCheck %s --check-prefix=CHECK-LONG < %t.out + +// Run w/o errors should not produce any log. +// RUN: rm -f %t.log.* +// RUN: ASAN_OPTIONS=log_path=%t.log %t ARG ARG ARG +// RUN: not cat %t.log.* + + +#include +#include +int main(int argc, char **argv) { + if (argc > 2) return 0; + char *x = (char*)malloc(10); + memset(x, 0, 10); + int res = x[argc * 10]; // BOOOM + free(x); + return res; +} +// CHECK-ERROR: ERROR: AddressSanitizer +// CHECK-INVALID: ERROR: Can't open file: /INVALID +// CHECK-LONG: ERROR: Path is too long: 01234 diff --git a/lib/asan/lit_tests/TestCases/log_path_fork_test.cc.disabled b/lib/asan/lit_tests/TestCases/log_path_fork_test.cc.disabled new file mode 100644 index 000000000000..c6c1b49e994d --- /dev/null +++ b/lib/asan/lit_tests/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: ASAN_OPTIONS="log_path=%t.log verbosity=1" not %t 2> %t.out +// RUN: for f in %t.log.* ; do FileCheck %s < $f; done +// RUN: [ `ls %t.log.* | wc -l` == 2 ] + +#include +#include +#include + +int main(int argc, char **argv) { + void *x = malloc(10); + free(x); + if (fork() == -1) return 1; + // There are two processes at this point, thus there should be two distinct + // error logs. + free(x); + return 0; +} + +// CHECK: ERROR: AddressSanitizer diff --git a/lib/asan/lit_tests/TestCases/lsan_annotations.cc b/lib/asan/lit_tests/TestCases/lsan_annotations.cc new file mode 100644 index 000000000000..c55ab8692eb5 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/lsan_annotations.cc @@ -0,0 +1,16 @@ +// Check that LSan annotations work fine. +// RUN: %clangxx_asan -O0 %s -o %t && %t +// RUN: %clangxx_asan -O3 %s -o %t && %t + +#include +#include + +int main() { + int *x = new int; + __lsan_ignore_object(x); + { + __lsan::ScopedDisabler disabler; + double *y = new double; + } + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/malloc_context_size.cc b/lib/asan/lit_tests/TestCases/malloc_context_size.cc new file mode 100644 index 000000000000..266ce66f59e2 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/malloc_context_size.cc @@ -0,0 +1,27 @@ +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=0 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os +// RUN: ASAN_OPTIONS=malloc_context_size=0:fast_unwind_on_malloc=1 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os +// RUN: ASAN_OPTIONS=malloc_context_size=1:fast_unwind_on_malloc=0 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os +// RUN: ASAN_OPTIONS=malloc_context_size=1:fast_unwind_on_malloc=1 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os + +int main() { + char *x = new char[20]; + delete[] x; + return x[0]; + // We need to keep duplicate lines with different 'CHECK-%os' prefixes, + // otherwise FileCheck barks on missing 'CHECK-%os' before 'CHECK-%os-NEXT'. + + // CHECK-Linux: freed by thread T{{.*}} here: + // CHECK-Linux-NEXT: #0 0x{{.*}} in operator delete[] + // CHECK-Darwin: freed by thread T{{.*}} here: + // CHECK-Darwin-NEXT: #0 0x{{.*}} in wrap__ZdaPv + // CHECK-NOT: #1 0x{{.*}} + + // CHECK-Linux: previously allocated by thread T{{.*}} here: + // CHECK-Linux-NEXT: #0 0x{{.*}} in operator new[] + // CHECK-Darwin: previously allocated by thread T{{.*}} here: + // CHECK-Darwin-NEXT: #0 0x{{.*}} in wrap__Znam + // CHECK-NOT: #1 0x{{.*}} + + // CHECK: SUMMARY: AddressSanitizer: heap-use-after-free +} diff --git a/lib/asan/lit_tests/TestCases/malloc_fill.cc b/lib/asan/lit_tests/TestCases/malloc_fill.cc new file mode 100644 index 000000000000..57f50d1438b7 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/malloc_fill.cc @@ -0,0 +1,22 @@ +// Check that we fill malloc-ed memory correctly. +// RUN: %clangxx_asan %s -o %t +// RUN: %t | FileCheck %s +// RUN: ASAN_OPTIONS=max_malloc_fill_size=10:malloc_fill_byte=8 %t | FileCheck %s --check-prefix=CHECK-10-8 +// RUN: ASAN_OPTIONS=max_malloc_fill_size=20:malloc_fill_byte=171 %t | FileCheck %s --check-prefix=CHECK-20-ab + +#include +int main(int argc, char **argv) { + // With asan allocator this makes sure we get memory from mmap. + static const int kSize = 1 << 25; + unsigned char *x = new unsigned char[kSize]; + printf("-"); + for (int i = 0; i <= 32; i++) { + printf("%02x", x[i]); + } + printf("-\n"); + delete [] x; +} + +// CHECK: -bebebebebebebebebebebebebebebebebebebebebebebebebebebebebebebebebe- +// CHECK-10-8: -080808080808080808080000000000000000000000000000000000000000000000- +// CHECK-20-ab: -abababababababababababababababababababab00000000000000000000000000- diff --git a/lib/asan/lit_tests/TestCases/malloc_hook.cc b/lib/asan/lit_tests/TestCases/malloc_hook.cc new file mode 100644 index 000000000000..83be1020ea43 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/malloc_hook.cc @@ -0,0 +1,36 @@ +// RUN: %clangxx_asan -O2 %s -o %t +// RUN: %t 2>&1 | FileCheck %s +#include +#include + +extern "C" { +bool __asan_get_ownership(const void *p); + +void *global_ptr; + +// Note: avoid calling functions that allocate memory in malloc/free +// to avoid infinite recursion. +void __asan_malloc_hook(void *ptr, size_t sz) { + if (__asan_get_ownership(ptr)) { + write(1, "MallocHook\n", sizeof("MallocHook\n")); + global_ptr = ptr; + } +} +void __asan_free_hook(void *ptr) { + if (__asan_get_ownership(ptr) && ptr == global_ptr) + write(1, "FreeHook\n", sizeof("FreeHook\n")); +} +} // extern "C" + +int main() { + volatile int *x = new int; + // CHECK: MallocHook + // Check that malloc hook was called with correct argument. + if (global_ptr != (void*)x) { + _exit(1); + } + *x = 0; + delete x; + // CHECK: FreeHook + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/memcmp_strict_test.cc b/lib/asan/lit_tests/TestCases/memcmp_strict_test.cc new file mode 100644 index 000000000000..e06a8c7e9e2f --- /dev/null +++ b/lib/asan/lit_tests/TestCases/memcmp_strict_test.cc @@ -0,0 +1,15 @@ +// RUN: %clangxx_asan -O0 %s -o %t && ASAN_OPTIONS=strict_memcmp=0 %t +// RUN: %clangxx_asan -O0 %s -o %t && ASAN_OPTIONS=strict_memcmp=1 not %t 2>&1 | FileCheck %s +// Default to strict_memcmp=1. +// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s + +#include +#include +int main() { + char kFoo[] = "foo"; + char kFubar[] = "fubar"; + int res = memcmp(kFoo, kFubar, strlen(kFubar)); + printf("res: %d\n", res); + // CHECK: AddressSanitizer: stack-buffer-overflow + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/memcmp_test.cc b/lib/asan/lit_tests/TestCases/memcmp_test.cc new file mode 100644 index 000000000000..758311ddc476 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/memcmp_test.cc @@ -0,0 +1,17 @@ +// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s + +// REQUIRES: compiler-rt-optimized + +#include +int main(int argc, char **argv) { + char a1[] = {argc, 2, 3, 4}; + char a2[] = {1, 2*argc, 3, 4}; + int res = memcmp(a1, a2, 4 + argc); // BOOM + // CHECK: AddressSanitizer: stack-buffer-overflow + // CHECK: {{#0.*memcmp}} + // CHECK: {{#1.*main}} + return res; +} diff --git a/lib/asan/lit_tests/TestCases/null_deref.cc b/lib/asan/lit_tests/TestCases/null_deref.cc new file mode 100644 index 000000000000..476418324cc5 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/null_deref.cc @@ -0,0 +1,19 @@ +// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK +// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK +// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK +// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK + +__attribute__((noinline)) +static void NullDeref(int *ptr) { + // CHECK: ERROR: AddressSanitizer: SEGV on unknown address + // CHECK: {{0x0*00028 .*pc 0x.*}} + ptr[10]++; // BOOM + // atos on Mac cannot extract the symbol name correctly. + // CHECK-Linux: {{ #0 0x.* in NullDeref.*null_deref.cc:}}[[@LINE-2]] + // CHECK-Darwin: {{ #0 0x.* in .*NullDeref.*null_deref.cc:}}[[@LINE-3]] +} +int main() { + NullDeref((int*)0); + // CHECK: {{ #1 0x.* in main.*null_deref.cc:}}[[@LINE-1]] + // CHECK: {{AddressSanitizer can not provide additional info.}} +} diff --git a/lib/asan/lit_tests/TestCases/on_error_callback.cc b/lib/asan/lit_tests/TestCases/on_error_callback.cc new file mode 100644 index 000000000000..d0cec2eb2703 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/on_error_callback.cc @@ -0,0 +1,16 @@ +// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s + +#include +#include + +extern "C" +void __asan_on_error() { + fprintf(stderr, "__asan_on_error called"); +} + +int main() { + char *x = (char*)malloc(10 * sizeof(char)); + free(x); + return x[5]; + // CHECK: __asan_on_error called +} diff --git a/lib/asan/lit_tests/TestCases/partial_right.cc b/lib/asan/lit_tests/TestCases/partial_right.cc new file mode 100644 index 000000000000..a000a913d6be --- /dev/null +++ b/lib/asan/lit_tests/TestCases/partial_right.cc @@ -0,0 +1,13 @@ +// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s + +#include +int main(int argc, char **argv) { + volatile int *x = (int*)malloc(2*sizeof(int) + 2); + int res = x[2]; // BOOOM + // CHECK: {{READ of size 4 at 0x.* thread T0}} + // CHECK: [[ADDR:0x[01-9a-fa-f]+]] is located 0 bytes to the right of {{.*}}-byte region [{{.*}},{{.*}}[[ADDR]]) + return res; +} diff --git a/lib/asan/lit_tests/TestCases/poison_partial.cc b/lib/asan/lit_tests/TestCases/poison_partial.cc new file mode 100644 index 000000000000..f7c48bf597b6 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/poison_partial.cc @@ -0,0 +1,19 @@ +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: not %t 2>&1 | FileCheck %s +// RUN: not %t heap 2>&1 | FileCheck %s +// RUN: ASAN_OPTIONS=poison_partial=0 %t +// RUN: ASAN_OPTIONS=poison_partial=0 %t heap +#include +char g[21]; +char *x; + +int main(int argc, char **argv) { + if (argc >= 2) + x = new char[21]; + else + x = &g[0]; + memset(x, 0, 21); + int *y = (int*)x; + return y[5]; +} +// CHECK: 0 bytes to the right diff --git a/lib/asan/lit_tests/TestCases/print_summary.cc b/lib/asan/lit_tests/TestCases/print_summary.cc new file mode 100644 index 000000000000..949c9b54f8a3 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/print_summary.cc @@ -0,0 +1,14 @@ +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: not %t 2>&1 | FileCheck %s --check-prefix=YES +// RUN: ASAN_OPTIONS=print_summary=false not %t 2>&1 | FileCheck %s --check-prefix=NO + +int main() { + char *x = new char[20]; + delete[] x; + return x[0]; + // YES: ERROR: AddressSanitizer: heap-use-after-free + // YES: SUMMARY: AddressSanitizer: heap-use-after-free + // NO: ERROR: AddressSanitizer: heap-use-after-free + // NO-NOT: SUMMARY: AddressSanitizer: heap-use-after-free +} + diff --git a/lib/asan/lit_tests/TestCases/readv.cc b/lib/asan/lit_tests/TestCases/readv.cc new file mode 100644 index 000000000000..ba17505f37ac --- /dev/null +++ b/lib/asan/lit_tests/TestCases/readv.cc @@ -0,0 +1,32 @@ +// RUN: %clangxx_asan -O0 %s -o %t && %t +// RUN: %clangxx_asan -O0 %s -DPOSITIVE -o %t && not %t 2>&1 | FileCheck %s + +// Test the readv() interceptor. + +#include +#include +#include +#include +#include +#include +#include + +int main() { + char buf[2011]; + struct iovec iov[2]; +#ifdef POSITIVE + char * volatile buf_ = buf; + iov[0].iov_base = buf_ - 1; +#else + iov[0].iov_base = buf + 1; +#endif + iov[0].iov_len = 5; + iov[1].iov_base = buf + 10; + iov[1].iov_len = 2000; + int fd = open("/etc/hosts", O_RDONLY); + assert(fd > 0); + readv(fd, iov, 2); + // CHECK: WRITE of size 5 at + close(fd); + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/sanity_check_pure_c.c b/lib/asan/lit_tests/TestCases/sanity_check_pure_c.c new file mode 100644 index 000000000000..df150675bd97 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/sanity_check_pure_c.c @@ -0,0 +1,19 @@ +// Sanity checking a test in pure C. +// RUN: %clang_asan -O2 %s -o %t +// RUN: not %t 2>&1 | FileCheck %s + +// Sanity checking a test in pure C with -pie. +// RUN: %clang_asan -O2 %s -pie -o %t +// RUN: not %t 2>&1 | FileCheck %s + +#include +int main() { + char *x = (char*)malloc(10 * sizeof(char)); + free(x); + return x[5]; + // CHECK: heap-use-after-free + // CHECK: free + // CHECK: main{{.*}}sanity_check_pure_c.c:[[@LINE-4]] + // CHECK: malloc + // CHECK: main{{.*}}sanity_check_pure_c.c:[[@LINE-7]] +} diff --git a/lib/asan/lit_tests/TestCases/shared-lib-test.cc b/lib/asan/lit_tests/TestCases/shared-lib-test.cc new file mode 100644 index 000000000000..126903a55866 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/shared-lib-test.cc @@ -0,0 +1,42 @@ +// RUN: %clangxx_asan -O0 %p/SharedLibs/shared-lib-test-so.cc \ +// RUN: -fPIC -shared -o %t-so.so +// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %p/SharedLibs/shared-lib-test-so.cc \ +// RUN: -fPIC -shared -o %t-so.so +// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %p/SharedLibs/shared-lib-test-so.cc \ +// RUN: -fPIC -shared -o %t-so.so +// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %p/SharedLibs/shared-lib-test-so.cc \ +// RUN: -fPIC -shared -o %t-so.so +// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s + +#include +#include +#include + +#include + +using std::string; + +typedef void (fun_t)(int x); + +int main(int argc, char *argv[]) { + string path = string(argv[0]) + "-so.so"; + printf("opening %s ... \n", path.c_str()); + void *lib = dlopen(path.c_str(), RTLD_NOW); + if (!lib) { + printf("error in dlopen(): %s\n", dlerror()); + return 1; + } + fun_t *inc = (fun_t*)dlsym(lib, "inc"); + if (!inc) return 1; + printf("ok\n"); + inc(1); + inc(-1); // BOOM + // CHECK: {{.*ERROR: AddressSanitizer: global-buffer-overflow}} + // CHECK: {{READ of size 4 at 0x.* thread T0}} + // CHECK: {{ #0 0x.*}} + // CHECK: {{ #1 0x.* in main .*shared-lib-test.cc:}}[[@LINE-4]] + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/sleep_before_dying.c b/lib/asan/lit_tests/TestCases/sleep_before_dying.c new file mode 100644 index 000000000000..8dee9f2778ce --- /dev/null +++ b/lib/asan/lit_tests/TestCases/sleep_before_dying.c @@ -0,0 +1,10 @@ +// RUN: %clang_asan -O2 %s -o %t +// RUN: ASAN_OPTIONS="sleep_before_dying=1" not %t 2>&1 | FileCheck %s + +#include +int main() { + char *x = (char*)malloc(10 * sizeof(char)); + free(x); + return x[5]; + // CHECK: Sleeping for 1 second +} diff --git a/lib/asan/lit_tests/TestCases/stack-buffer-overflow-with-position.cc b/lib/asan/lit_tests/TestCases/stack-buffer-overflow-with-position.cc new file mode 100644 index 000000000000..91820db0142a --- /dev/null +++ b/lib/asan/lit_tests/TestCases/stack-buffer-overflow-with-position.cc @@ -0,0 +1,45 @@ +// RUN: %clangxx_asan -O2 %s -o %t +// RUN: not %t -2 2>&1 | FileCheck --check-prefix=CHECK-m2 %s +// RUN: not %t -1 2>&1 | FileCheck --check-prefix=CHECK-m1 %s +// RUN: %t 0 +// RUN: %t 8 +// RUN: not %t 9 2>&1 | FileCheck --check-prefix=CHECK-9 %s +// RUN: not %t 10 2>&1 | FileCheck --check-prefix=CHECK-10 %s +// RUN: not %t 62 2>&1 | FileCheck --check-prefix=CHECK-62 %s +// RUN: not %t 63 2>&1 | FileCheck --check-prefix=CHECK-63 %s +// RUN: not %t 63 2>&1 | FileCheck --check-prefix=CHECK-63 %s +// RUN: not %t 73 2>&1 | FileCheck --check-prefix=CHECK-73 %s +// RUN: not %t 74 2>&1 | FileCheck --check-prefix=CHECK-74 %s +// RUN: not %t 126 2>&1 | FileCheck --check-prefix=CHECK-126 %s +// RUN: not %t 127 2>&1 | FileCheck --check-prefix=CHECK-127 %s +// RUN: not %t 137 2>&1 | FileCheck --check-prefix=CHECK-137 %s +// RUN: not %t 138 2>&1 | FileCheck --check-prefix=CHECK-138 %s +#include +#include +#include +#include +int main(int argc, char **argv) { + assert(argc >= 2); + int idx = atoi(argv[1]); + char AAA[10], BBB[10], CCC[10]; + memset(AAA, 0, sizeof(AAA)); + memset(BBB, 0, sizeof(BBB)); + memset(CCC, 0, sizeof(CCC)); + int res = 0; + char *p = AAA + idx; + printf("AAA: %p\ny: %p\nz: %p\np: %p\n", AAA, BBB, CCC, p); + // make sure BBB and CCC are not removed; + return *(short*)(p) + BBB[argc % 2] + CCC[argc % 2]; +} +// CHECK-m2: 'AAA' <== Memory access at offset 30 underflows this variable +// CHECK-m1: 'AAA' <== Memory access at offset 31 partially underflows this variable +// CHECK-9: 'AAA' <== Memory access at offset 41 partially overflows this variable +// CHECK-10: 'AAA' <== Memory access at offset 42 overflows this variable +// CHECK-62: 'BBB' <== Memory access at offset 94 underflows this variable +// CHECK-63: 'BBB' <== Memory access at offset 95 partially underflows this variable +// CHECK-73: 'BBB' <== Memory access at offset 105 partially overflows this variable +// CHECK-74: 'BBB' <== Memory access at offset 106 overflows this variable +// CHECK-126: 'CCC' <== Memory access at offset 158 underflows this variable +// CHECK-127: 'CCC' <== Memory access at offset 159 partially underflows this variable +// CHECK-137: 'CCC' <== Memory access at offset 169 partially overflows this variable +// CHECK-138: 'CCC' <== Memory access at offset 170 overflows this variable diff --git a/lib/asan/lit_tests/TestCases/stack-frame-demangle.cc b/lib/asan/lit_tests/TestCases/stack-frame-demangle.cc new file mode 100644 index 000000000000..2b83ecc2923b --- /dev/null +++ b/lib/asan/lit_tests/TestCases/stack-frame-demangle.cc @@ -0,0 +1,22 @@ +// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s + +#include + +namespace XXX { +struct YYY { + static int ZZZ(int x) { + char array[10]; + memset(array, 0, 10); + return array[x]; // BOOOM + // CHECK: ERROR: AddressSanitizer: stack-buffer-overflow + // CHECK: READ of size 1 at + // CHECK: is located in stack of thread T0 at offset + // CHECK: XXX::YYY::ZZZ + } +}; +} // namespace XXX + +int main(int argc, char **argv) { + int res = XXX::YYY::ZZZ(argc + 10); + return res; +} diff --git a/lib/asan/lit_tests/TestCases/stack-oob-frames.cc b/lib/asan/lit_tests/TestCases/stack-oob-frames.cc new file mode 100644 index 000000000000..909e700b3d00 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/stack-oob-frames.cc @@ -0,0 +1,59 @@ +// RUN: %clangxx_asan -O1 %s -o %t +// RUN: not %t 0 2>&1 | FileCheck %s --check-prefix=CHECK0 +// RUN: not %t 1 2>&1 | FileCheck %s --check-prefix=CHECK1 +// RUN: not %t 2 2>&1 | FileCheck %s --check-prefix=CHECK2 +// RUN: not %t 3 2>&1 | FileCheck %s --check-prefix=CHECK3 + +#define NOINLINE __attribute__((noinline)) +inline void break_optimization(void *arg) { + __asm__ __volatile__("" : : "r" (arg) : "memory"); +} + +NOINLINE static void Frame0(int frame, char *a, char *b, char *c) { + char s[4] = {0}; + char *d = s; + break_optimization(&d); + switch (frame) { + case 3: a[5]++; break; + case 2: b[5]++; break; + case 1: c[5]++; break; + case 0: d[5]++; break; + } +} +NOINLINE static void Frame1(int frame, char *a, char *b) { + char c[4] = {0}; Frame0(frame, a, b, c); + break_optimization(0); +} +NOINLINE static void Frame2(int frame, char *a) { + char b[4] = {0}; Frame1(frame, a, b); + break_optimization(0); +} +NOINLINE static void Frame3(int frame) { + char a[4] = {0}; Frame2(frame, a); + break_optimization(0); +} + +int main(int argc, char **argv) { + if (argc != 2) return 1; + Frame3(argv[1][0] - '0'); +} + +// CHECK0: AddressSanitizer: stack-buffer-overflow +// CHECK0: #0{{.*}}Frame0 +// CHECK0: #1{{.*}}Frame1 +// CHECK0: #2{{.*}}Frame2 +// CHECK0: #3{{.*}}Frame3 +// CHECK0: is located in stack of thread T0 at offset +// CHECK0-NEXT: #0{{.*}}Frame0 +// +// CHECK1: AddressSanitizer: stack-buffer-overflow +// CHECK1: is located in stack of thread T0 at offset +// CHECK1-NEXT: #0{{.*}}Frame1 +// +// CHECK2: AddressSanitizer: stack-buffer-overflow +// CHECK2: is located in stack of thread T0 at offset +// CHECK2-NEXT: #0{{.*}}Frame2 +// +// CHECK3: AddressSanitizer: stack-buffer-overflow +// CHECK3: is located in stack of thread T0 at offset +// CHECK3-NEXT: #0{{.*}}Frame3 diff --git a/lib/asan/lit_tests/TestCases/stack-overflow.cc b/lib/asan/lit_tests/TestCases/stack-overflow.cc new file mode 100644 index 000000000000..adf1c0784f70 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/stack-overflow.cc @@ -0,0 +1,16 @@ +// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s + +#include +int main(int argc, char **argv) { + char x[10]; + memset(x, 0, 10); + int res = x[argc * 10]; // BOOOM + // CHECK: {{READ of size 1 at 0x.* thread T0}} + // CHECK: {{ #0 0x.* in main .*stack-overflow.cc:}}[[@LINE-2]] + // CHECK: {{Address 0x.* is located in stack of thread T0 at offset}} + // CHECK-NEXT: in{{.*}}main{{.*}}stack-overflow.cc + return res; +} diff --git a/lib/asan/lit_tests/TestCases/stack-use-after-return.cc b/lib/asan/lit_tests/TestCases/stack-use-after-return.cc new file mode 100644 index 000000000000..5ed42a8c0c97 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/stack-use-after-return.cc @@ -0,0 +1,77 @@ +// RUN: export ASAN_OPTIONS=detect_stack_use_after_return=1 +// RUN: %clangxx_asan -O0 %s -o %t && \ +// RUN: not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %s -o %t && \ +// RUN: not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -o %t && \ +// RUN: not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -o %t && \ +// RUN: not %t 2>&1 | FileCheck %s +// RUN: ASAN_OPTIONS=detect_stack_use_after_return=0 %t +// Regression test for a CHECK failure with small stack size and large frame. +// RUN: %clangxx_asan -O3 %s -o %t -DkSize=10000 && \ +// RUN: (ulimit -s 65; not %t) 2>&1 | FileCheck %s +// +// Test that we can find UAR in a thread other than main: +// RUN: %clangxx_asan -DUseThread -O2 %s -o %t && \ +// RUN: not %t 2>&1 | FileCheck --check-prefix=THREAD %s +// +// Test the uar_stack_size_log flag. +// +// RUN: ASAN_OPTIONS=$ASAN_OPTIONS:uar_stack_size_log=20:verbosity=1 not %t 2>&1 | FileCheck --check-prefix=CHECK-20 %s +// RUN: ASAN_OPTIONS=$ASAN_OPTIONS:uar_stack_size_log=24:verbosity=1 not %t 2>&1 | FileCheck --check-prefix=CHECK-24 %s + +#include +#include + +#ifndef kSize +# define kSize 1 +#endif + +#ifndef UseThread +# define UseThread 0 +#endif + +__attribute__((noinline)) +char *Ident(char *x) { + fprintf(stderr, "1: %p\n", x); + return x; +} + +__attribute__((noinline)) +char *Func1() { + char local[kSize]; + return Ident(local); +} + +__attribute__((noinline)) +void Func2(char *x) { + fprintf(stderr, "2: %p\n", x); + *x = 1; + // CHECK: WRITE of size 1 {{.*}} thread T0 + // CHECK: #0{{.*}}Func2{{.*}}stack-use-after-return.cc:[[@LINE-2]] + // CHECK: is located in stack of thread T0 at offset + // CHECK: 'local' <== Memory access at offset 32 is inside this variable + // THREAD: WRITE of size 1 {{.*}} thread T{{[1-9]}} + // THREAD: #0{{.*}}Func2{{.*}}stack-use-after-return.cc:[[@LINE-6]] + // THREAD: is located in stack of thread T{{[1-9]}} at offset + // THREAD: 'local' <== Memory access at offset 32 is inside this variable + // CHECK-20: T0: FakeStack created:{{.*}} stack_size_log: 20 + // CHECK-24: T0: FakeStack created:{{.*}} stack_size_log: 24 +} + +void *Thread(void *unused) { + Func2(Func1()); + return NULL; +} + +int main(int argc, char **argv) { +#if UseThread + pthread_t t; + pthread_create(&t, 0, Thread, 0); + pthread_join(t, 0); +#else + Func2(Func1()); +#endif + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/strdup_oob_test.cc b/lib/asan/lit_tests/TestCases/strdup_oob_test.cc new file mode 100644 index 000000000000..e92afd3caaf9 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/strdup_oob_test.cc @@ -0,0 +1,19 @@ +// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s + +#include + +char kString[] = "foo"; + +int main(int argc, char **argv) { + char *copy = strdup(kString); + int x = copy[4 + argc]; // BOOM + // CHECK: AddressSanitizer: heap-buffer-overflow + // CHECK: #0 {{.*}}main {{.*}}strdup_oob_test.cc:[[@LINE-2]] + // CHECK: allocated by thread T{{.*}} here: + // CHECK: #0 {{.*}}strdup + // CHECK: strdup_oob_test.cc:[[@LINE-6]] + return x; +} diff --git a/lib/asan/lit_tests/TestCases/strerror_r_test.cc b/lib/asan/lit_tests/TestCases/strerror_r_test.cc new file mode 100644 index 000000000000..0df009b83f9c --- /dev/null +++ b/lib/asan/lit_tests/TestCases/strerror_r_test.cc @@ -0,0 +1,13 @@ +// RUN: %clangxx_asan -O0 %s -o %t && %t + +// Regression test for PR17138. + +#include +#include + +int main() { + char buf[1024]; + char *res = (char *)strerror_r(300, buf, sizeof(buf)); + assert(res != 0); + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/strip_path_prefix.c b/lib/asan/lit_tests/TestCases/strip_path_prefix.c new file mode 100644 index 000000000000..c4d6ba49d5e3 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/strip_path_prefix.c @@ -0,0 +1,12 @@ +// RUN: %clang_asan -O2 %s -o %t +// RUN: ASAN_OPTIONS="strip_path_prefix='/'" not %t 2>&1 | FileCheck %s + +#include +int main() { + char *x = (char*)malloc(10 * sizeof(char)); + free(x); + return x[5]; + // Check that paths in error report don't start with slash. + // CHECK: heap-use-after-free + // CHECK-NOT: #0 0x{{.*}} ({{[/].*}}) +} diff --git a/lib/asan/lit_tests/TestCases/strncpy-overflow.cc b/lib/asan/lit_tests/TestCases/strncpy-overflow.cc new file mode 100644 index 000000000000..f91e191fde23 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/strncpy-overflow.cc @@ -0,0 +1,28 @@ +// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK +// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK +// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK +// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK + +// REQUIRES: compiler-rt-optimized + +#include +#include +int main(int argc, char **argv) { + char *hello = (char*)malloc(6); + strcpy(hello, "hello"); + char *short_buffer = (char*)malloc(9); + strncpy(short_buffer, hello, 10); // BOOM + // CHECK: {{WRITE of size 10 at 0x.* thread T0}} + // CHECK-Linux: {{ #0 0x.* in .*strncpy}} + // CHECK-Darwin: {{ #0 0x.* in wrap_strncpy}} + // CHECK: {{ #1 0x.* in main .*strncpy-overflow.cc:}}[[@LINE-4]] + // CHECK: {{0x.* is located 0 bytes to the right of 9-byte region}} + // CHECK: {{allocated by thread T0 here:}} + + // CHECK-Linux: {{ #0 0x.* in .*malloc}} + // CHECK-Linux: {{ #1 0x.* in main .*strncpy-overflow.cc:}}[[@LINE-10]] + + // CHECK-Darwin: {{ #0 0x.* in wrap_malloc.*}} + // CHECK-Darwin: {{ #1 0x.* in main .*strncpy-overflow.cc:}}[[@LINE-13]] + return short_buffer[8]; +} diff --git a/lib/asan/lit_tests/TestCases/symbolize_callback.cc b/lib/asan/lit_tests/TestCases/symbolize_callback.cc new file mode 100644 index 000000000000..058b3150fbba --- /dev/null +++ b/lib/asan/lit_tests/TestCases/symbolize_callback.cc @@ -0,0 +1,17 @@ +// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s + +#include +#include + +extern "C" +bool __asan_symbolize(const void *pc, char *out_buffer, int out_size) { + snprintf(out_buffer, out_size, "MySymbolizer"); + return true; +} + +int main() { + char *x = (char*)malloc(10 * sizeof(char)); + free(x); + return x[5]; + // CHECK: MySymbolizer +} diff --git a/lib/asan/lit_tests/TestCases/throw_call_test.cc b/lib/asan/lit_tests/TestCases/throw_call_test.cc new file mode 100644 index 000000000000..974bc51d97c5 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/throw_call_test.cc @@ -0,0 +1,45 @@ +// RUN: %clangxx_asan %s -o %t && %t +// http://code.google.com/p/address-sanitizer/issues/detail?id=147 (not fixed). +// BROKEN: %clangxx_asan %s -o %t -static-libstdc++ && %t +#include +static volatile int zero = 0; +inline void pretend_to_do_something(void *x) { + __asm__ __volatile__("" : : "r" (x) : "memory"); +} + +__attribute__((noinline, no_sanitize_address)) +void ReallyThrow() { + fprintf(stderr, "ReallyThrow\n"); + if (zero == 0) + throw 42; +} + +__attribute__((noinline)) +void Throw() { + int a, b, c, d, e; + pretend_to_do_something(&a); + pretend_to_do_something(&b); + pretend_to_do_something(&c); + pretend_to_do_something(&d); + pretend_to_do_something(&e); + fprintf(stderr, "Throw stack = %p\n", &a); + ReallyThrow(); +} + +__attribute__((noinline)) +void CheckStack() { + int ar[100]; + pretend_to_do_something(ar); + for (int i = 0; i < 100; i++) + ar[i] = i; + fprintf(stderr, "CheckStack stack = %p, %p\n", ar, ar + 100); +} + +int main(int argc, char** argv) { + try { + Throw(); + } catch(int a) { + fprintf(stderr, "a = %d\n", a); + } + CheckStack(); +} diff --git a/lib/asan/lit_tests/TestCases/throw_invoke_test.cc b/lib/asan/lit_tests/TestCases/throw_invoke_test.cc new file mode 100644 index 000000000000..077a940e8d19 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/throw_invoke_test.cc @@ -0,0 +1,50 @@ +// RUN: %clangxx_asan %s -o %t && %t +// RUN: %clangxx_asan %s -o %t -static-libstdc++ && %t +#include +static volatile int zero = 0; +inline void pretend_to_do_something(void *x) { + __asm__ __volatile__("" : : "r" (x) : "memory"); +} + +__attribute__((noinline)) +void ReallyThrow() { + fprintf(stderr, "ReallyThrow\n"); + try { + if (zero == 0) + throw 42; + else if (zero == 1) + throw 1.; + } catch(double x) { + } +} + +__attribute__((noinline)) +void Throw() { + int a, b, c, d, e; + pretend_to_do_something(&a); + pretend_to_do_something(&b); + pretend_to_do_something(&c); + pretend_to_do_something(&d); + pretend_to_do_something(&e); + fprintf(stderr, "Throw stack = %p\n", &a); + ReallyThrow(); +} + +__attribute__((noinline)) +void CheckStack() { + int ar[100]; + pretend_to_do_something(ar); + for (int i = 0; i < 100; i++) + ar[i] = i; + fprintf(stderr, "CheckStack stack = %p, %p\n", ar, ar + 100); +} + +int main(int argc, char** argv) { + try { + Throw(); + } catch(int a) { + fprintf(stderr, "a = %d\n", a); + } + CheckStack(); +} + diff --git a/lib/asan/lit_tests/TestCases/time_interceptor.cc b/lib/asan/lit_tests/TestCases/time_interceptor.cc new file mode 100644 index 000000000000..3be00d60c01d --- /dev/null +++ b/lib/asan/lit_tests/TestCases/time_interceptor.cc @@ -0,0 +1,16 @@ +// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s + +// Test the time() interceptor. + +#include +#include +#include + +int main() { + time_t *tm = (time_t*)malloc(sizeof(time_t)); + free(tm); + time_t t = time(tm); + printf("Time: %s\n", ctime(&t)); // NOLINT + // CHECK: use-after-free + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/uar_and_exceptions.cc b/lib/asan/lit_tests/TestCases/uar_and_exceptions.cc new file mode 100644 index 000000000000..c967531c2c02 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/uar_and_exceptions.cc @@ -0,0 +1,40 @@ +// Test that use-after-return works with exceptions. +// export ASAN_OPTIONS=detect_stack_use_after_return=1 +// RUN: %clangxx_asan -O0 %s -o %t && %t + +#include + +volatile char *g; + +#ifndef FRAME_SIZE +# define FRAME_SIZE 100 +#endif + +#ifndef NUM_ITER +# define NUM_ITER 4000 +#endif + +#ifndef DO_THROW +# define DO_THROW 1 +#endif + +void Func(int depth) { + char frame[FRAME_SIZE]; + g = &frame[0]; + if (depth) + Func(depth - 1); + else if (DO_THROW) + throw 1; +} + +int main(int argc, char **argv) { + for (int i = 0; i < NUM_ITER; i++) { + try { + Func(argc * 100); + } catch(...) { + } + if ((i % (NUM_ITER / 10)) == 0) + fprintf(stderr, "done [%d]\n", i); + } + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/unaligned_loads_and_stores.cc b/lib/asan/lit_tests/TestCases/unaligned_loads_and_stores.cc new file mode 100644 index 000000000000..d50566c44e9a --- /dev/null +++ b/lib/asan/lit_tests/TestCases/unaligned_loads_and_stores.cc @@ -0,0 +1,52 @@ +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: not %t A 2>&1 | FileCheck --check-prefix=CHECK-A %s +// RUN: not %t B 2>&1 | FileCheck --check-prefix=CHECK-B %s +// RUN: not %t C 2>&1 | FileCheck --check-prefix=CHECK-C %s +// RUN: not %t D 2>&1 | FileCheck --check-prefix=CHECK-D %s +// RUN: not %t E 2>&1 | FileCheck --check-prefix=CHECK-E %s + +// RUN: not %t K 2>&1 | FileCheck --check-prefix=CHECK-K %s +// RUN: not %t L 2>&1 | FileCheck --check-prefix=CHECK-L %s +// RUN: not %t M 2>&1 | FileCheck --check-prefix=CHECK-M %s +// RUN: not %t N 2>&1 | FileCheck --check-prefix=CHECK-N %s +// RUN: not %t O 2>&1 | FileCheck --check-prefix=CHECK-O %s + +#include + +#include +#include +int main(int argc, char **argv) { + if (argc != 2) return 1; + char *x = new char[16]; + memset(x, 0xab, 16); + int res = 1; + switch (argv[1][0]) { + case 'A': res = __sanitizer_unaligned_load16(x + 15); break; +// CHECK-A ERROR: AddressSanitizer: heap-buffer-overflow on address +// CHECK-A: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-2]] +// CHECK-A: is located 0 bytes to the right of 16-byte region + case 'B': res = __sanitizer_unaligned_load32(x + 14); break; +// CHECK-B: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]] + case 'C': res = __sanitizer_unaligned_load32(x + 13); break; +// CHECK-C: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]] + case 'D': res = __sanitizer_unaligned_load64(x + 15); break; +// CHECK-D: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]] + case 'E': res = __sanitizer_unaligned_load64(x + 9); break; +// CHECK-E: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]] + + case 'K': __sanitizer_unaligned_store16(x + 15, 0); break; +// CHECK-K ERROR: AddressSanitizer: heap-buffer-overflow on address +// CHECK-K: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-2]] +// CHECK-K: is located 0 bytes to the right of 16-byte region + case 'L': __sanitizer_unaligned_store32(x + 15, 0); break; +// CHECK-L: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]] + case 'M': __sanitizer_unaligned_store32(x + 13, 0); break; +// CHECK-M: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]] + case 'N': __sanitizer_unaligned_store64(x + 10, 0); break; +// CHECK-N: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]] + case 'O': __sanitizer_unaligned_store64(x + 14, 0); break; +// CHECK-O: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]] + } + delete x; + return res; +} diff --git a/lib/asan/lit_tests/TestCases/use-after-free-right.cc b/lib/asan/lit_tests/TestCases/use-after-free-right.cc new file mode 100644 index 000000000000..88d91f53d24e --- /dev/null +++ b/lib/asan/lit_tests/TestCases/use-after-free-right.cc @@ -0,0 +1,34 @@ +// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK +// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK +// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK +// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK + +// Test use-after-free report in the case when access is at the right border of +// the allocation. + +#include +int main() { + volatile char *x = (char*)malloc(sizeof(char)); + free((void*)x); + *x = 42; + // CHECK: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}} + // CHECK: {{0x.* at pc 0x.* bp 0x.* sp 0x.*}} + // CHECK: {{WRITE of size 1 at 0x.* thread T0}} + // CHECK: {{ #0 0x.* in main .*use-after-free-right.cc:13}} + // CHECK: {{0x.* is located 0 bytes inside of 1-byte region .0x.*,0x.*}} + // CHECK: {{freed by thread T0 here:}} + + // CHECK-Linux: {{ #0 0x.* in .*free}} + // CHECK-Linux: {{ #1 0x.* in main .*use-after-free-right.cc:12}} + + // CHECK-Darwin: {{ #0 0x.* in wrap_free}} + // CHECK-Darwin: {{ #1 0x.* in main .*use-after-free-right.cc:12}} + + // CHECK: {{previously allocated by thread T0 here:}} + + // CHECK-Linux: {{ #0 0x.* in .*malloc}} + // CHECK-Linux: {{ #1 0x.* in main .*use-after-free-right.cc:11}} + + // CHECK-Darwin: {{ #0 0x.* in wrap_malloc.*}} + // CHECK-Darwin: {{ #1 0x.* in main .*use-after-free-right.cc:11}} +} diff --git a/lib/asan/lit_tests/TestCases/use-after-free.cc b/lib/asan/lit_tests/TestCases/use-after-free.cc new file mode 100644 index 000000000000..84ba479c1393 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/use-after-free.cc @@ -0,0 +1,31 @@ +// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK +// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK +// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK +// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK + +#include +int main() { + char *x = (char*)malloc(10 * sizeof(char)); + free(x); + return x[5]; + // CHECK: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}} + // CHECK: {{0x.* at pc 0x.* bp 0x.* sp 0x.*}} + // CHECK: {{READ of size 1 at 0x.* thread T0}} + // CHECK: {{ #0 0x.* in main .*use-after-free.cc:10}} + // CHECK: {{0x.* is located 5 bytes inside of 10-byte region .0x.*,0x.*}} + // CHECK: {{freed by thread T0 here:}} + + // CHECK-Linux: {{ #0 0x.* in .*free}} + // CHECK-Linux: {{ #1 0x.* in main .*use-after-free.cc:9}} + + // CHECK-Darwin: {{ #0 0x.* in wrap_free}} + // CHECK-Darwin: {{ #1 0x.* in main .*use-after-free.cc:9}} + + // CHECK: {{previously allocated by thread T0 here:}} + + // CHECK-Linux: {{ #0 0x.* in .*malloc}} + // CHECK-Linux: {{ #1 0x.* in main .*use-after-free.cc:8}} + + // CHECK-Darwin: {{ #0 0x.* in wrap_malloc.*}} + // CHECK-Darwin: {{ #1 0x.* in main .*use-after-free.cc:8}} +} diff --git a/lib/asan/lit_tests/TestCases/use-after-poison.cc b/lib/asan/lit_tests/TestCases/use-after-poison.cc new file mode 100644 index 000000000000..e3bc6ecee7f2 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/use-after-poison.cc @@ -0,0 +1,20 @@ +// Check that __asan_poison_memory_region works. +// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s +// +// Check that we can disable it +// RUN: ASAN_OPTIONS=allow_user_poisoning=0 %t + +#include + +extern "C" void __asan_poison_memory_region(void *, size_t); + +int main(int argc, char **argv) { + char *x = new char[16]; + x[10] = 0; + __asan_poison_memory_region(x, 16); + int res = x[argc * 10]; // BOOOM + // CHECK: ERROR: AddressSanitizer: use-after-poison + // CHECK: main{{.*}}use-after-poison.cc:[[@LINE-2]] + delete [] x; + return res; +} diff --git a/lib/asan/lit_tests/TestCases/use-after-scope-dtor-order.cc b/lib/asan/lit_tests/TestCases/use-after-scope-dtor-order.cc new file mode 100644 index 000000000000..32fa6ad8a464 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/use-after-scope-dtor-order.cc @@ -0,0 +1,25 @@ +// RUN: %clangxx_asan -O0 -fsanitize=use-after-scope %s -o %t && \ +// RUN: not %t 2>&1 | FileCheck %s +#include + +struct IntHolder { + explicit IntHolder(int *val = 0) : val_(val) { } + ~IntHolder() { + printf("Value: %d\n", *val_); // BOOM + // CHECK: ERROR: AddressSanitizer: stack-use-after-scope + // CHECK: #0 0x{{.*}} in IntHolder::~IntHolder{{.*}}use-after-scope-dtor-order.cc:[[@LINE-2]] + } + void set(int *val) { val_ = val; } + int *get() { return val_; } + + int *val_; +}; + +int main(int argc, char *argv[]) { + // It is incorrect to use "x" int IntHolder destructor, because "x" is + // "destroyed" earlier as it's declared later. + IntHolder holder; + int x = argc; + holder.set(&x); + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/use-after-scope-inlined.cc b/lib/asan/lit_tests/TestCases/use-after-scope-inlined.cc new file mode 100644 index 000000000000..0bad048e3b8f --- /dev/null +++ b/lib/asan/lit_tests/TestCases/use-after-scope-inlined.cc @@ -0,0 +1,27 @@ +// Test with "-O2" only to make sure inlining (leading to use-after-scope) +// happens. "always_inline" is not enough, as Clang doesn't emit +// llvm.lifetime intrinsics at -O0. +// +// RUN: %clangxx_asan -O2 -fsanitize=use-after-scope %s -o %t && not %t 2>&1 | FileCheck %s + +int *arr; + +__attribute__((always_inline)) +void inlined(int arg) { + int x[5]; + for (int i = 0; i < arg; i++) x[i] = i; + arr = x; +} + +int main(int argc, char *argv[]) { + inlined(argc); + return arr[argc - 1]; // BOOM + // CHECK: ERROR: AddressSanitizer: stack-use-after-scope + // CHECK: READ of size 4 at 0x{{.*}} thread T0 + // CHECK: #0 0x{{.*}} in main + // CHECK: {{.*}}use-after-scope-inlined.cc:[[@LINE-4]] + // CHECK: Address 0x{{.*}} is located in stack of thread T0 at offset + // CHECK: [[OFFSET:[^ ]*]] in frame + // CHECK: main + // CHECK: {{\[}}[[OFFSET]], {{.*}}) 'x.i' +} diff --git a/lib/asan/lit_tests/TestCases/use-after-scope-nobug.cc b/lib/asan/lit_tests/TestCases/use-after-scope-nobug.cc new file mode 100644 index 000000000000..c23acf76eaee --- /dev/null +++ b/lib/asan/lit_tests/TestCases/use-after-scope-nobug.cc @@ -0,0 +1,14 @@ +// RUN: %clangxx_asan -O0 -fsanitize=use-after-scope %s -o %t && %t + +#include + +int main() { + int *p = 0; + // Variable goes in and out of scope. + for (int i = 0; i < 3; i++) { + int x = 0; + p = &x; + } + printf("PASSED\n"); + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/use-after-scope-temp.cc b/lib/asan/lit_tests/TestCases/use-after-scope-temp.cc new file mode 100644 index 000000000000..13d714f9def7 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/use-after-scope-temp.cc @@ -0,0 +1,29 @@ +// RUN: %clangxx_asan -O0 -fsanitize=use-after-scope %s -o %t && \ +// RUN: %t 2>&1 | FileCheck %s +// +// Lifetime for temporaries is not emitted yet. +// XFAIL: * + +#include + +struct IntHolder { + explicit IntHolder(int val) : val(val) { + printf("IntHolder: %d\n", val); + } + int val; +}; + +const IntHolder *saved; + +void save(const IntHolder &holder) { + saved = &holder; +} + +int main(int argc, char *argv[]) { + save(IntHolder(10)); + int x = saved->val; // BOOM + // CHECK: ERROR: AddressSanitizer: stack-use-after-scope + // CHECK: #0 0x{{.*}} in main {{.*}}use-after-scope-temp.cc:[[@LINE-2]] + printf("saved value: %d\n", x); + return 0; +} diff --git a/lib/asan/lit_tests/TestCases/use-after-scope.cc b/lib/asan/lit_tests/TestCases/use-after-scope.cc new file mode 100644 index 000000000000..c46c9594c314 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/use-after-scope.cc @@ -0,0 +1,16 @@ +// RUN: %clangxx_asan -O0 -fsanitize=use-after-scope %s -o %t && \ +// RUN: not %t 2>&1 | FileCheck %s +// RUN: ASAN_OPTIONS="detect_stack_use_after_return=1" not %t 2>&1 | FileCheck %s + +int main() { + int *p = 0; + { + int x = 0; + p = &x; + } + return *p; // BOOM + // CHECK: ERROR: AddressSanitizer: stack-use-after-scope + // CHECK: #0 0x{{.*}} in main {{.*}}use-after-scope.cc:[[@LINE-2]] + // CHECK: Address 0x{{.*}} is located in stack of thread T{{.*}} at offset [[OFFSET:[^ ]+]] in frame + // {{\[}}[[OFFSET]], {{[0-9]+}}) 'x' +} diff --git a/lib/asan/lit_tests/TestCases/wait.cc b/lib/asan/lit_tests/TestCases/wait.cc new file mode 100644 index 000000000000..b5580dc88675 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/wait.cc @@ -0,0 +1,63 @@ +// RUN: %clangxx_asan -DWAIT -O0 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -DWAIT -O3 %s -o %t && not %t 2>&1 | FileCheck %s + +// RUN: %clangxx_asan -DWAITPID -O0 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -DWAITPID -O3 %s -o %t && not %t 2>&1 | FileCheck %s + +// RUN: %clangxx_asan -DWAITID -O0 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -DWAITID -O3 %s -o %t && not %t 2>&1 | FileCheck %s + +// RUN: %clangxx_asan -DWAIT3 -O0 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -DWAIT3 -O3 %s -o %t && not %t 2>&1 | FileCheck %s + +// RUN: %clangxx_asan -DWAIT4 -O0 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -DWAIT4 -O3 %s -o %t && not %t 2>&1 | FileCheck %s + +// RUN: %clangxx_asan -DWAIT3_RUSAGE -O0 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -DWAIT3_RUSAGE -O3 %s -o %t && not %t 2>&1 | FileCheck %s + +// RUN: %clangxx_asan -DWAIT4_RUSAGE -O0 %s -o %t && not %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -DWAIT4_RUSAGE -O3 %s -o %t && not %t 2>&1 | FileCheck %s + + +#include +#include +#include + +int main(int argc, char **argv) { + pid_t pid = fork(); + if (pid) { // parent + int x[3]; + int *status = x + argc * 3; + int res; +#if defined(WAIT) + res = wait(status); +#elif defined(WAITPID) + res = waitpid(pid, status, WNOHANG); +#elif defined(WAITID) + siginfo_t *si = (siginfo_t*)(x + argc * 3); + res = waitid(P_ALL, 0, si, WEXITED | WNOHANG); +#elif defined(WAIT3) + res = wait3(status, WNOHANG, NULL); +#elif defined(WAIT4) + res = wait4(pid, status, WNOHANG, NULL); +#elif defined(WAIT3_RUSAGE) || defined(WAIT4_RUSAGE) + struct rusage *ru = (struct rusage*)(x + argc * 3); + int good_status; +# if defined(WAIT3_RUSAGE) + res = wait3(&good_status, WNOHANG, ru); +# elif defined(WAIT4_RUSAGE) + res = wait4(pid, &good_status, WNOHANG, ru); +# endif +#endif + // CHECK: stack-buffer-overflow + // CHECK: {{WRITE of size .* at 0x.* thread T0}} + // CHECK: {{in .*wait}} + // CHECK: {{in main .*wait.cc:}} + // CHECK: is located in stack of thread T0 at offset + // CHECK: {{in main}} + return res != -1; + } + // child + return 0; +} diff --git a/lib/asan/lit_tests/Unit/lit.cfg b/lib/asan/lit_tests/Unit/lit.cfg deleted file mode 100644 index e24361b014e9..000000000000 --- a/lib/asan/lit_tests/Unit/lit.cfg +++ /dev/null @@ -1,26 +0,0 @@ -# -*- Python -*- - -import os - -def get_required_attr(config, attr_name): - attr_value = getattr(config, attr_name, None) - if not attr_value: - lit.fatal("No attribute %r in test configuration! You may need to run " - "tests from your build directory or add this attribute " - "to lit.site.cfg " % attr_name) - return attr_value - -# Setup attributes common for all compiler-rt projects. -compiler_rt_src_root = get_required_attr(config, 'compiler_rt_src_root') -compiler_rt_lit_unit_cfg = os.path.join(compiler_rt_src_root, "lib", - "lit.common.unit.cfg") -lit.load_config(config, compiler_rt_lit_unit_cfg) - -# Setup config name. -config.name = 'AddressSanitizer-Unit' - -# Setup test source and exec root. For unit tests, we define -# it as build directory with ASan unit tests. -asan_binary_dir = get_required_attr(config, "asan_binary_dir") -config.test_exec_root = os.path.join(asan_binary_dir, "tests") -config.test_source_root = config.test_exec_root diff --git a/lib/asan/lit_tests/Unit/lit.site.cfg.in b/lib/asan/lit_tests/Unit/lit.site.cfg.in index 315d24d1ed09..a45870c9b0e1 100644 --- a/lib/asan/lit_tests/Unit/lit.site.cfg.in +++ b/lib/asan/lit_tests/Unit/lit.site.cfg.in @@ -1,17 +1,16 @@ ## Autogenerated by LLVM/Clang configuration. # Do not edit! -config.target_triple = "@TARGET_TRIPLE@" -config.llvm_src_root = "@LLVM_SOURCE_DIR@" -config.compiler_rt_src_root = "@COMPILER_RT_SOURCE_DIR@" -config.llvm_build_mode = "@LLVM_BUILD_MODE@" -config.asan_binary_dir = "@ASAN_BINARY_DIR@" +# Load common config for all compiler-rt unit tests. +lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.unit.configured") -try: - config.llvm_build_mode = config.llvm_build_mode % lit.params -except KeyError,e: - key, = e.args - lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key)) +# Setup config name. +config.name = 'AddressSanitizer-Unit' -# Let the main config do the real work. -lit.load_config(config, "@ASAN_SOURCE_DIR@/lit_tests/Unit/lit.cfg") +# Setup test source and exec root. For unit tests, we define +# it as build directory with ASan unit tests. +config.test_exec_root = "@ASAN_BINARY_DIR@/tests" +config.test_source_root = config.test_exec_root + +if config.host_os == 'Linux': + config.environment['ASAN_OPTIONS'] = 'detect_leaks=1' diff --git a/lib/asan/lit_tests/allow_user_segv.cc b/lib/asan/lit_tests/allow_user_segv.cc deleted file mode 100644 index f8aed0d4ca80..000000000000 --- a/lib/asan/lit_tests/allow_user_segv.cc +++ /dev/null @@ -1,50 +0,0 @@ -// Regression test for -// https://code.google.com/p/address-sanitizer/issues/detail?id=180 - -// RUN: %clangxx_asan -m64 -O0 %s -o %t && ASAN_OPTIONS=allow_user_segv_handler=true %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m64 -O2 %s -o %t && ASAN_OPTIONS=allow_user_segv_handler=true %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m32 -O0 %s -o %t && ASAN_OPTIONS=allow_user_segv_handler=true %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m32 -O2 %s -o %t && ASAN_OPTIONS=allow_user_segv_handler=true %t 2>&1 | FileCheck %s - -#include -#include - -struct sigaction user_sigaction; -struct sigaction original_sigaction; - -void User_OnSIGSEGV(int signum, siginfo_t *siginfo, void *context) { - fprintf(stderr, "User sigaction called\n"); - if (original_sigaction.sa_flags | SA_SIGINFO) - original_sigaction.sa_sigaction(signum, siginfo, context); - else - original_sigaction.sa_handler(signum); -} - -int DoSEGV() { - volatile int *x = 0; - return *x; -} - -int main() { - user_sigaction.sa_sigaction = User_OnSIGSEGV; - user_sigaction.sa_flags = SA_SIGINFO; -#if defined(__APPLE__) && !defined(__LP64__) - // On 32-bit Darwin KERN_PROTECTION_FAILURE (SIGBUS) is delivered. - int signum = SIGBUS; -#else - // On 64-bit Darwin KERN_INVALID_ADDRESS (SIGSEGV) is delivered. - // On Linux SIGSEGV is delivered as well. - int signum = SIGSEGV; -#endif - if (sigaction(signum, &user_sigaction, &original_sigaction)) { - perror("sigaction"); - return 1; - } - fprintf(stderr, "User sigaction installed\n"); - return DoSEGV(); -} - -// CHECK: User sigaction installed -// CHECK-NEXT: User sigaction called -// CHECK-NEXT: ASAN:SIGSEGV -// CHECK: AddressSanitizer: SEGV on unknown address diff --git a/lib/asan/lit_tests/blacklist.cc b/lib/asan/lit_tests/blacklist.cc deleted file mode 100644 index 6cfc1500c503..000000000000 --- a/lib/asan/lit_tests/blacklist.cc +++ /dev/null @@ -1,44 +0,0 @@ -// Test the blacklist functionality of ASan - -// RUN: echo "fun:*brokenFunction*" > %tmp -// RUN: echo "global:*badGlobal*" >> %tmp -// RUN: echo "src:*blacklist-extra.cc" >> %tmp -// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -m64 -O0 %s -o %t \ -// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1 -// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -m64 -O1 %s -o %t \ -// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1 -// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -m64 -O2 %s -o %t \ -// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1 -// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -m64 -O3 %s -o %t \ -// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1 -// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -m32 -O0 %s -o %t \ -// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1 -// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -m32 -O1 %s -o %t \ -// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1 -// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -m32 -O2 %s -o %t \ -// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1 -// RUN: %clangxx_asan -fsanitize-blacklist=%tmp -m32 -O3 %s -o %t \ -// RUN: %p/Helpers/blacklist-extra.cc && %t 2>&1 - -// badGlobal is accessed improperly, but we blacklisted it. -int badGlobal; -int readBadGlobal() { - return (&badGlobal)[1]; -} - -// A function which is broken, but excluded in the blacklist. -int brokenFunction(int argc) { - char x[10] = {0}; - return x[argc * 10]; // BOOM -} - -// This function is defined in Helpers/blacklist-extra.cc, a source file which -// is blacklisted by name -int externalBrokenFunction(int x); - -int main(int argc, char **argv) { - brokenFunction(argc); - int x = readBadGlobal(); - externalBrokenFunction(argc); - return 0; -} diff --git a/lib/asan/lit_tests/deep_stack_uaf.cc b/lib/asan/lit_tests/deep_stack_uaf.cc deleted file mode 100644 index 7b32798fefcc..000000000000 --- a/lib/asan/lit_tests/deep_stack_uaf.cc +++ /dev/null @@ -1,36 +0,0 @@ -// Check that we can store lots of stack frames if asked to. - -// RUN: %clangxx_asan -m64 -O0 %s -o %t 2>&1 -// RUN: ASAN_OPTIONS=malloc_context_size=120:redzone=512 %t 2>&1 | \ -// RUN: %symbolize | FileCheck %s - -// RUN: %clangxx_asan -m32 -O0 %s -o %t 2>&1 -// RUN: ASAN_OPTIONS=malloc_context_size=120:redzone=512 %t 2>&1 | \ -// RUN: %symbolize | FileCheck %s -#include -#include - -template -struct DeepFree { - static void free(char *x) { - DeepFree::free(x); - } -}; - -template<> -struct DeepFree<0> { - static void free(char *x) { - ::free(x); - } -}; - -int main() { - char *x = (char*)malloc(10); - // deep_free(x); - DeepFree<200>::free(x); - return x[5]; - // CHECK: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}} - // CHECK: DeepFree<36> - // CHECK: DeepFree<98> - // CHECK: DeepFree<115> -} diff --git a/lib/asan/lit_tests/deep_tail_call.cc b/lib/asan/lit_tests/deep_tail_call.cc deleted file mode 100644 index 6aa15e81f6ec..000000000000 --- a/lib/asan/lit_tests/deep_tail_call.cc +++ /dev/null @@ -1,24 +0,0 @@ -// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s - -// CHECK: AddressSanitizer: global-buffer-overflow -int global[10]; -// CHECK: {{#0.*call4}} -void __attribute__((noinline)) call4(int i) { global[i+10]++; } -// CHECK: {{#1.*call3}} -void __attribute__((noinline)) call3(int i) { call4(i); } -// CHECK: {{#2.*call2}} -void __attribute__((noinline)) call2(int i) { call3(i); } -// CHECK: {{#3.*call1}} -void __attribute__((noinline)) call1(int i) { call2(i); } -// CHECK: {{#4.*main}} -int main(int argc, char **argv) { - call1(argc); - return global[0]; -} diff --git a/lib/asan/lit_tests/deep_thread_stack.cc b/lib/asan/lit_tests/deep_thread_stack.cc deleted file mode 100644 index 781508d61616..000000000000 --- a/lib/asan/lit_tests/deep_thread_stack.cc +++ /dev/null @@ -1,61 +0,0 @@ -// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s - -#include - -int *x; - -void *AllocThread(void *arg) { - x = new int; - *x = 42; - return NULL; -} - -void *FreeThread(void *arg) { - delete x; - return NULL; -} - -void *AccessThread(void *arg) { - *x = 43; // BOOM - return NULL; -} - -typedef void* (*callback_type)(void* arg); - -void *RunnerThread(void *function) { - pthread_t thread; - pthread_create(&thread, NULL, (callback_type)function, NULL); - pthread_join(thread, NULL); - return NULL; -} - -void RunThread(callback_type function) { - pthread_t runner; - pthread_create(&runner, NULL, RunnerThread, (void*)function); - pthread_join(runner, NULL); -} - -int main(int argc, char *argv[]) { - RunThread(AllocThread); - RunThread(FreeThread); - RunThread(AccessThread); - return (x != 0); -} - -// CHECK: AddressSanitizer: heap-use-after-free -// CHECK: WRITE of size 4 at 0x{{.*}} thread T[[ACCESS_THREAD:[0-9]+]] -// CHECK: freed by thread T[[FREE_THREAD:[0-9]+]] here: -// CHECK: previously allocated by thread T[[ALLOC_THREAD:[0-9]+]] here: -// CHECK: Thread T[[ACCESS_THREAD]] created by T[[ACCESS_RUNNER:[0-9]+]] here: -// CHECK: Thread T[[ACCESS_RUNNER]] created by T0 here: -// CHECK: Thread T[[FREE_THREAD]] created by T[[FREE_RUNNER:[0-9]+]] here: -// CHECK: Thread T[[FREE_RUNNER]] created by T0 here: -// CHECK: Thread T[[ALLOC_THREAD]] created by T[[ALLOC_RUNNER:[0-9]+]] here: -// CHECK: Thread T[[ALLOC_RUNNER]] created by T0 here: diff --git a/lib/asan/lit_tests/default_blacklist.cc b/lib/asan/lit_tests/default_blacklist.cc deleted file mode 100644 index 25a1ae1752b0..000000000000 --- a/lib/asan/lit_tests/default_blacklist.cc +++ /dev/null @@ -1,3 +0,0 @@ -// Test that ASan uses the default blacklist from resource directory. -// RUN: %clangxx_asan -### %s 2>&1 | FileCheck %s -// CHECK: fsanitize-blacklist={{.*}}asan_blacklist.txt diff --git a/lib/asan/lit_tests/default_options.cc b/lib/asan/lit_tests/default_options.cc deleted file mode 100644 index 84b80557b852..000000000000 --- a/lib/asan/lit_tests/default_options.cc +++ /dev/null @@ -1,15 +0,0 @@ -// RUN: %clangxx_asan -O2 %s -o %t -// RUN: %t 2>&1 | FileCheck %s - -const char *kAsanDefaultOptions="verbosity=1 foo=bar"; - -extern "C" -__attribute__((no_sanitize_address)) -const char *__asan_default_options() { - // CHECK: Using the defaults from __asan_default_options: {{.*}} foo=bar - return kAsanDefaultOptions; -} - -int main() { - return 0; -} diff --git a/lib/asan/lit_tests/dlclose-test.cc b/lib/asan/lit_tests/dlclose-test.cc deleted file mode 100644 index b15895bf3579..000000000000 --- a/lib/asan/lit_tests/dlclose-test.cc +++ /dev/null @@ -1,93 +0,0 @@ -// Regression test for -// http://code.google.com/p/address-sanitizer/issues/detail?id=19 -// Bug description: -// 1. application dlopens foo.so -// 2. asan registers all globals from foo.so -// 3. application dlcloses foo.so -// 4. application mmaps some memory to the location where foo.so was before -// 5. application starts using this mmaped memory, but asan still thinks there -// are globals. -// 6. BOOM - -// This sublte test assumes that after a foo.so is dlclose-d -// we can mmap the region of memory that has been occupied by the library. -// It works on i368/x86_64 Linux, but not necessary anywhere else. -// REQUIRES: x86_64-supported-target,i386-supported-target - -// RUN: %clangxx_asan -m64 -O0 %p/SharedLibs/dlclose-test-so.cc \ -// RUN: -fPIC -shared -o %t-so.so -// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m64 -O1 %p/SharedLibs/dlclose-test-so.cc \ -// RUN: -fPIC -shared -o %t-so.so -// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m64 -O2 %p/SharedLibs/dlclose-test-so.cc \ -// RUN: -fPIC -shared -o %t-so.so -// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m64 -O3 %p/SharedLibs/dlclose-test-so.cc \ -// RUN: -fPIC -shared -o %t-so.so -// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m32 -O0 %p/SharedLibs/dlclose-test-so.cc \ -// RUN: -fPIC -shared -o %t-so.so -// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m32 -O1 %p/SharedLibs/dlclose-test-so.cc \ -// RUN: -fPIC -shared -o %t-so.so -// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m32 -O2 %p/SharedLibs/dlclose-test-so.cc \ -// RUN: -fPIC -shared -o %t-so.so -// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m32 -O3 %p/SharedLibs/dlclose-test-so.cc \ -// RUN: -fPIC -shared -o %t-so.so -// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | FileCheck %s - -#include -#include -#include -#include -#include -#include - -#include - -using std::string; - -typedef int *(fun_t)(); - -int main(int argc, char *argv[]) { - string path = string(argv[0]) + "-so.so"; - size_t PageSize = sysconf(_SC_PAGESIZE); - printf("opening %s ... \n", path.c_str()); - void *lib = dlopen(path.c_str(), RTLD_NOW); - if (!lib) { - printf("error in dlopen(): %s\n", dlerror()); - return 1; - } - fun_t *get = (fun_t*)dlsym(lib, "get_address_of_static_var"); - if (!get) { - printf("failed dlsym\n"); - return 1; - } - int *addr = get(); - assert(((size_t)addr % 32) == 0); // should be 32-byte aligned. - printf("addr: %p\n", addr); - addr[0] = 1; // make sure we can write there. - - // Now dlclose the shared library. - printf("attempting to dlclose\n"); - if (dlclose(lib)) { - printf("failed to dlclose\n"); - return 1; - } - // Now, the page where 'addr' is unmapped. Map it. - size_t page_beg = ((size_t)addr) & ~(PageSize - 1); - void *res = mmap((void*)(page_beg), PageSize, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 0, 0); - if (res == (char*)-1L) { - printf("failed to mmap\n"); - return 1; - } - addr[1] = 2; // BOOM (if the bug is not fixed). - printf("PASS\n"); - // CHECK: PASS - return 0; -} diff --git a/lib/asan/lit_tests/double-free.cc b/lib/asan/lit_tests/double-free.cc deleted file mode 100644 index 9e201117c563..000000000000 --- a/lib/asan/lit_tests/double-free.cc +++ /dev/null @@ -1,18 +0,0 @@ -// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s - -#include -#include -int main(int argc, char **argv) { - char *x = (char*)malloc(10 * sizeof(char)); - memset(x, 0, 10); - int res = x[argc]; - free(x); - free(x + argc - 1); // BOOM - // CHECK: AddressSanitizer: attempting double-free{{.*}}in thread T0 - // CHECK: double-free.cc:[[@LINE-2]] - // CHECK: freed by thread T0 here: - // CHECK: double-free.cc:[[@LINE-5]] - // CHECK: allocated by thread T0 here: - // CHECK: double-free.cc:[[@LINE-10]] - return res; -} diff --git a/lib/asan/lit_tests/force_inline_opt0.cc b/lib/asan/lit_tests/force_inline_opt0.cc deleted file mode 100644 index 955ce38156fb..000000000000 --- a/lib/asan/lit_tests/force_inline_opt0.cc +++ /dev/null @@ -1,14 +0,0 @@ -// This test checks that we are no instrumenting a memory access twice -// (before and after inlining) -// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t -// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t -__attribute__((always_inline)) -void foo(int *x) { - *x = 0; -} - -int main() { - int x; - foo(&x); - return x; -} diff --git a/lib/asan/lit_tests/global-demangle.cc b/lib/asan/lit_tests/global-demangle.cc deleted file mode 100644 index 5696a38a7705..000000000000 --- a/lib/asan/lit_tests/global-demangle.cc +++ /dev/null @@ -1,18 +0,0 @@ -// Don't run through %symbolize to avoid c++filt demangling. -// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | FileCheck %s - -namespace XXX { -class YYY { - public: - static char ZZZ[]; -}; -char YYY::ZZZ[] = "abc"; -} - -int main(int argc, char **argv) { - return (int)XXX::YYY::ZZZ[argc + 5]; // BOOM - // CHECK: {{READ of size 1 at 0x.*}} - // CHECK: {{0x.* is located 2 bytes to the right of global variable}} - // CHECK: 'XXX::YYY::ZZZ' {{.*}} of size 4 - // CHECK: 'XXX::YYY::ZZZ' is ascii string 'abc' -} diff --git a/lib/asan/lit_tests/global-overflow.cc b/lib/asan/lit_tests/global-overflow.cc deleted file mode 100644 index 6a2f12e106fe..000000000000 --- a/lib/asan/lit_tests/global-overflow.cc +++ /dev/null @@ -1,25 +0,0 @@ -// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s - -#include -int main(int argc, char **argv) { - static char XXX[10]; - static char YYY[10]; - static char ZZZ[10]; - memset(XXX, 0, 10); - memset(YYY, 0, 10); - memset(ZZZ, 0, 10); - int res = YYY[argc * 10]; // BOOOM - // CHECK: {{READ of size 1 at 0x.* thread T0}} - // CHECK: {{ #0 0x.* in _?main .*global-overflow.cc:}}[[@LINE-2]] - // CHECK: {{0x.* is located 0 bytes to the right of global variable}} - // CHECK: {{.*YYY.* of size 10}} - res += XXX[argc] + ZZZ[argc]; - return res; -} diff --git a/lib/asan/lit_tests/heap-overflow.cc b/lib/asan/lit_tests/heap-overflow.cc deleted file mode 100644 index f1d719cd0b20..000000000000 --- a/lib/asan/lit_tests/heap-overflow.cc +++ /dev/null @@ -1,36 +0,0 @@ -// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out - -#include -#include -int main(int argc, char **argv) { - char *x = (char*)malloc(10 * sizeof(char)); - memset(x, 0, 10); - int res = x[argc * 10]; // BOOOM - // CHECK: {{READ of size 1 at 0x.* thread T0}} - // CHECK: {{ #0 0x.* in _?main .*heap-overflow.cc:}}[[@LINE-2]] - // CHECK: {{0x.* is located 0 bytes to the right of 10-byte region}} - // CHECK: {{allocated by thread T0 here:}} - - // CHECK-Linux: {{ #0 0x.* in .*malloc}} - // CHECK-Linux: {{ #1 0x.* in main .*heap-overflow.cc:21}} - - // CHECK-Darwin: {{ #0 0x.* in _?wrap_malloc.*}} - // CHECK-Darwin: {{ #1 0x.* in _?main .*heap-overflow.cc:21}} - free(x); - return res; -} diff --git a/lib/asan/lit_tests/huge_negative_hea_oob.cc b/lib/asan/lit_tests/huge_negative_hea_oob.cc deleted file mode 100644 index a09e3bf87d60..000000000000 --- a/lib/asan/lit_tests/huge_negative_hea_oob.cc +++ /dev/null @@ -1,13 +0,0 @@ -// RUN: %clangxx_asan -m64 %s -o %t && %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -m64 -O %s -o %t && %t 2>&1 | FileCheck %s -// Check that we can find huge buffer overflows to the left. -#include -#include -int main(int argc, char **argv) { - char *x = (char*)malloc(1 << 20); - memset(x, 0, 10); - int res = x[-argc * 4000]; // BOOOM - // CHECK: is located 4000 bytes to the left of - free(x); - return res; -} diff --git a/lib/asan/lit_tests/init-order-atexit.cc b/lib/asan/lit_tests/init-order-atexit.cc deleted file mode 100644 index 45f4f17c0cb0..000000000000 --- a/lib/asan/lit_tests/init-order-atexit.cc +++ /dev/null @@ -1,31 +0,0 @@ -// Test for the following situation: -// (1) global A is constructed. -// (2) exit() is called during construction of global B. -// (3) destructor of A reads uninitialized global C from another module. -// We do *not* want to report init-order bug in this case. - -// RUN: %clangxx_asan -m64 -O0 %s %p/Helpers/init-order-atexit-extra.cc -o %t -// RUN: ASAN_OPTIONS=check_initialization_order=true:strict_init_order=true %t 2>&1 | FileCheck %s - -#include -#include - -void AccessC(); - -class A { - public: - A() { } - ~A() { AccessC(); printf("PASSED\n"); } - // CHECK-NOT: AddressSanitizer - // CHECK: PASSED -}; - -A a; - -class B { - public: - B() { exit(1); } - ~B() { } -}; - -B b; diff --git a/lib/asan/lit_tests/init-order-dlopen.cc b/lib/asan/lit_tests/init-order-dlopen.cc deleted file mode 100644 index 228f44204c99..000000000000 --- a/lib/asan/lit_tests/init-order-dlopen.cc +++ /dev/null @@ -1,52 +0,0 @@ -// Regression test for -// https://code.google.com/p/address-sanitizer/issues/detail?id=178 - -// RUN: %clangxx_asan -m64 -O0 %p/SharedLibs/init-order-dlopen-so.cc \ -// RUN: -fPIC -shared -o %t-so.so -// If the linker doesn't support --export-dynamic (which is ELF-specific), -// try to link without that option. -// FIXME: find a better solution. -// RUN: %clangxx_asan -m64 -O0 %s -o %t -Wl,--export-dynamic || \ -// RUN: %clangxx_asan -m64 -O0 %s -o %t -// RUN: ASAN_OPTIONS=check_initialization_order=true:strict_init_order=true %t 2>&1 | FileCheck %s -#include -#include -#include -#include - -#include - -using std::string; - -int foo() { - return 42; -} -int global = foo(); - -__attribute__((visibility("default"))) -void inc_global() { - global++; -} - -void *global_poller(void *arg) { - while (true) { - if (global != 42) - break; - usleep(100); - } - return 0; -} - -int main(int argc, char *argv[]) { - pthread_t p; - pthread_create(&p, 0, global_poller, 0); - string path = string(argv[0]) + "-so.so"; - if (0 == dlopen(path.c_str(), RTLD_NOW)) { - fprintf(stderr, "dlerror: %s\n", dlerror()); - return 1; - } - pthread_join(p, 0); - printf("PASSED\n"); - // CHECK: PASSED - return 0; -} diff --git a/lib/asan/lit_tests/initialization-blacklist.cc b/lib/asan/lit_tests/initialization-blacklist.cc deleted file mode 100644 index 12fbc49ed91b..000000000000 --- a/lib/asan/lit_tests/initialization-blacklist.cc +++ /dev/null @@ -1,47 +0,0 @@ -// Test for blacklist functionality of initialization-order checker. - -// RUN: %clangxx_asan -m64 -O0 %s %p/Helpers/initialization-blacklist-extra.cc\ -// RUN: %p/Helpers/initialization-blacklist-extra2.cc \ -// RUN: -fsanitize-blacklist=%p/Helpers/initialization-blacklist.txt \ -// RUN: -fsanitize=init-order -o %t -// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 -// RUN: %clangxx_asan -m64 -O1 %s %p/Helpers/initialization-blacklist-extra.cc\ -// RUN: %p/Helpers/initialization-blacklist-extra2.cc \ -// RUN: -fsanitize-blacklist=%p/Helpers/initialization-blacklist.txt \ -// RUN: -fsanitize=init-order -o %t -// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 -// RUN: %clangxx_asan -m64 -O2 %s %p/Helpers/initialization-blacklist-extra.cc\ -// RUN: %p/Helpers/initialization-blacklist-extra2.cc \ -// RUN: -fsanitize-blacklist=%p/Helpers/initialization-blacklist.txt \ -// RUN: -fsanitize=init-order -o %t -// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 -// RUN: %clangxx_asan -m32 -O0 %s %p/Helpers/initialization-blacklist-extra.cc\ -// RUN: %p/Helpers/initialization-blacklist-extra2.cc \ -// RUN: -fsanitize-blacklist=%p/Helpers/initialization-blacklist.txt \ -// RUN: -fsanitize=init-order -o %t -// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 -// RUN: %clangxx_asan -m32 -O1 %s %p/Helpers/initialization-blacklist-extra.cc\ -// RUN: %p/Helpers/initialization-blacklist-extra2.cc \ -// RUN: -fsanitize-blacklist=%p/Helpers/initialization-blacklist.txt \ -// RUN: -fsanitize=init-order -o %t -// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 -// RUN: %clangxx_asan -m32 -O2 %s %p/Helpers/initialization-blacklist-extra.cc\ -// RUN: %p/Helpers/initialization-blacklist-extra2.cc \ -// RUN: -fsanitize-blacklist=%p/Helpers/initialization-blacklist.txt \ -// RUN: -fsanitize=init-order -o %t -// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 - -// Function is defined in another TU. -int readBadGlobal(); -int x = readBadGlobal(); // init-order bug. - -// Function is defined in another TU. -int accessBadObject(); -int y = accessBadObject(); // init-order bug. - -int readBadSrcGlobal(); -int z = readBadSrcGlobal(); // init-order bug. - -int main(int argc, char **argv) { - return argc + x + y + z - 1; -} diff --git a/lib/asan/lit_tests/initialization-bug.cc b/lib/asan/lit_tests/initialization-bug.cc deleted file mode 100644 index ee2c725f0b13..000000000000 --- a/lib/asan/lit_tests/initialization-bug.cc +++ /dev/null @@ -1,49 +0,0 @@ -// Test to make sure basic initialization order errors are caught. - -// RUN: %clangxx_asan -m64 -O0 %s %p/Helpers/initialization-bug-extra2.cc -o %t -// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 \ -// RUN: | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O0 %s %p/Helpers/initialization-bug-extra2.cc -o %t -// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 \ -// RUN: | %symbolize | FileCheck %s - -// 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 - -// The structure of the test is: -// "x", "y", "z" are dynamically initialized globals. -// Value of "x" depends on "y", value of "y" depends on "z". -// "x" and "z" are defined in this TU, "y" is defined in another one. -// Thus we shoud stably report initialization order fiasco independently of -// the translation unit order. - -int initZ() { - return 5; -} -int z = initZ(); - -// 'y' is a dynamically initialized global residing in a different TU. This -// dynamic initializer will read the value of 'y' before main starts. The -// result is undefined behavior, which should be caught by initialization order -// checking. -extern int y; -int __attribute__((noinline)) initX() { - return y + 1; - // CHECK: {{AddressSanitizer: initialization-order-fiasco}} - // CHECK: {{READ of size .* at 0x.* thread T0}} - // CHECK: {{0x.* is located 0 bytes inside of global variable .*(y|z).*}} -} - -// This initializer begins our initialization order problems. -static int x = initX(); - -int main() { - // ASan should have caused an exit before main runs. - printf("PASS\n"); - // CHECK-NOT: PASS - return 0; -} diff --git a/lib/asan/lit_tests/initialization-constexpr.cc b/lib/asan/lit_tests/initialization-constexpr.cc deleted file mode 100644 index ba5410674f76..000000000000 --- a/lib/asan/lit_tests/initialization-constexpr.cc +++ /dev/null @@ -1,43 +0,0 @@ -// Constexpr: -// We need to check that a global variable initialized with a constexpr -// constructor can be accessed during dynamic initialization (as a constexpr -// constructor implies that it was initialized during constant initialization, -// not dynamic initialization). - -// RUN: %clangxx_asan -m64 -O0 %s %p/Helpers/initialization-constexpr-extra.cc\ -// RUN: --std=c++11 -fsanitize=init-order -o %t -// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 -// RUN: %clangxx_asan -m64 -O1 %s %p/Helpers/initialization-constexpr-extra.cc\ -// RUN: --std=c++11 -fsanitize=init-order -o %t -// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 -// RUN: %clangxx_asan -m64 -O2 %s %p/Helpers/initialization-constexpr-extra.cc\ -// RUN: --std=c++11 -fsanitize=init-order -o %t -// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 -// RUN: %clangxx_asan -m64 -O3 %s %p/Helpers/initialization-constexpr-extra.cc\ -// RUN: --std=c++11 -fsanitize=init-order -o %t -// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 -// RUN: %clangxx_asan -m32 -O0 %s %p/Helpers/initialization-constexpr-extra.cc\ -// RUN: --std=c++11 -fsanitize=init-order -o %t -// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 -// RUN: %clangxx_asan -m32 -O1 %s %p/Helpers/initialization-constexpr-extra.cc\ -// RUN: --std=c++11 -fsanitize=init-order -o %t -// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 -// RUN: %clangxx_asan -m32 -O2 %s %p/Helpers/initialization-constexpr-extra.cc\ -// RUN: --std=c++11 -fsanitize=init-order -o %t -// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 -// RUN: %clangxx_asan -m32 -O3 %s %p/Helpers/initialization-constexpr-extra.cc\ -// RUN: --std=c++11 -fsanitize=init-order -o %t -// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 - -class Integer { - private: - int value; - - public: - constexpr Integer(int x = 0) : value(x) {} - int getValue() {return value;} -}; -Integer coolestInteger(42); -int getCoolestInteger() { return coolestInteger.getValue(); } - -int main() { return 0; } diff --git a/lib/asan/lit_tests/initialization-nobug.cc b/lib/asan/lit_tests/initialization-nobug.cc deleted file mode 100644 index 407226e29a1b..000000000000 --- a/lib/asan/lit_tests/initialization-nobug.cc +++ /dev/null @@ -1,56 +0,0 @@ -// A collection of various initializers which shouldn't trip up initialization -// order checking. If successful, this will just return 0. - -// RUN: %clangxx_asan -m64 -O0 %s %p/Helpers/initialization-nobug-extra.cc -fsanitize=init-order -o %t -// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 -// RUN: %clangxx_asan -m64 -O1 %s %p/Helpers/initialization-nobug-extra.cc -fsanitize=init-order -o %t -// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 -// RUN: %clangxx_asan -m64 -O2 %s %p/Helpers/initialization-nobug-extra.cc -fsanitize=init-order -o %t -// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 -// RUN: %clangxx_asan -m64 -O3 %s %p/Helpers/initialization-nobug-extra.cc -fsanitize=init-order -o %t -// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 -// RUN: %clangxx_asan -m32 -O0 %s %p/Helpers/initialization-nobug-extra.cc -fsanitize=init-order -o %t -// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 -// RUN: %clangxx_asan -m32 -O1 %s %p/Helpers/initialization-nobug-extra.cc -fsanitize=init-order -o %t -// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 -// RUN: %clangxx_asan -m32 -O2 %s %p/Helpers/initialization-nobug-extra.cc -fsanitize=init-order -o %t -// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 -// RUN: %clangxx_asan -m32 -O3 %s %p/Helpers/initialization-nobug-extra.cc -fsanitize=init-order -o %t -// RUN: ASAN_OPTIONS=check_initialization_order=true %t 2>&1 - -// Simple access: -// Make sure that accessing a global in the same TU is safe - -bool condition = true; -int initializeSameTU() { - return condition ? 0x2a : 052; -} -int sameTU = initializeSameTU(); - -// Linker initialized: -// Check that access to linker initialized globals originating from a different -// TU's initializer is safe. - -int A = (1 << 1) + (1 << 3) + (1 << 5), B; -int getAB() { - return A * B; -} - -// Function local statics: -// Check that access to function local statics originating from a different -// TU's initializer is safe. - -int countCalls() { - static int calls; - return ++calls; -} - -// Trivial constructor, non-trivial destructor. -struct StructWithDtor { - ~StructWithDtor() { } - int value; -}; -StructWithDtor struct_with_dtor; -int getStructWithDtorValue() { return struct_with_dtor.value; } - -int main() { return 0; } diff --git a/lib/asan/lit_tests/interface_test.cc b/lib/asan/lit_tests/interface_test.cc deleted file mode 100644 index 428a109fe70d..000000000000 --- a/lib/asan/lit_tests/interface_test.cc +++ /dev/null @@ -1,8 +0,0 @@ -// Check that user may include ASan interface header. -// RUN: %clang -fsanitize=address -I %p/../../../include %s -o %t && %t -// RUN: %clang -I %p/../../../include %s -o %t && %t -#include - -int main() { - return 0; -} diff --git a/lib/asan/lit_tests/invalid-free.cc b/lib/asan/lit_tests/invalid-free.cc deleted file mode 100644 index 0ef064056b63..000000000000 --- a/lib/asan/lit_tests/invalid-free.cc +++ /dev/null @@ -1,16 +0,0 @@ -// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s - -#include -#include -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: - // CHECK: invalid-free.cc:[[@LINE-8]] - return res; -} diff --git a/lib/asan/lit_tests/large_func_test.cc b/lib/asan/lit_tests/large_func_test.cc deleted file mode 100644 index ceecc29b7b0a..000000000000 --- a/lib/asan/lit_tests/large_func_test.cc +++ /dev/null @@ -1,63 +0,0 @@ -// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out - -#include -__attribute__((noinline)) -static void LargeFunction(int *x, int zero) { - x[0]++; - x[1]++; - x[2]++; - x[3]++; - x[4]++; - x[5]++; - x[6]++; - x[7]++; - x[8]++; - x[9]++; - - // CHECK: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}} - // CHECK: {{0x.* at pc 0x.* bp 0x.* sp 0x.*}} - // CHECK: {{READ of size 4 at 0x.* thread T0}} - x[zero + 103]++; // we should report this exact line - // atos incorrectly extracts the symbol name for the static functions on - // Darwin. - // CHECK-Linux: {{#0 0x.* in LargeFunction.*large_func_test.cc:}}[[@LINE-3]] - // CHECK-Darwin: {{#0 0x.* in .*LargeFunction.*large_func_test.cc}}:[[@LINE-4]] - - x[10]++; - x[11]++; - x[12]++; - x[13]++; - x[14]++; - x[15]++; - x[16]++; - x[17]++; - x[18]++; - x[19]++; -} - -int main(int argc, char **argv) { - int *x = new int[100]; - LargeFunction(x, argc - 1); - // CHECK: {{ #1 0x.* in _?main .*large_func_test.cc:}}[[@LINE-1]] - // CHECK: {{0x.* is located 12 bytes to the right of 400-byte region}} - // CHECK: {{allocated by thread T0 here:}} - // CHECK-Linux: {{ #0 0x.* in operator new.*}} - // CHECK-Darwin: {{ #0 0x.* in .*_Zna.*}} - // CHECK: {{ #1 0x.* in _?main .*large_func_test.cc:}}[[@LINE-7]] - delete x; -} diff --git a/lib/asan/lit_tests/lit.cfg b/lib/asan/lit_tests/lit.cfg index 5daecd9e557d..71a700c6ac3b 100644 --- a/lib/asan/lit_tests/lit.cfg +++ b/lib/asan/lit_tests/lit.cfg @@ -2,24 +2,27 @@ import os +import lit.util + def get_required_attr(config, attr_name): attr_value = getattr(config, attr_name, None) if not attr_value: - lit.fatal("No attribute %r in test configuration! You may need to run " - "tests from your build directory or add this attribute " - "to lit.site.cfg " % attr_name) + lit_config.fatal( + "No attribute %r in test configuration! You may need to run " + "tests from your build directory or add this attribute " + "to lit.site.cfg " % attr_name) return attr_value # Setup config name. -config.name = 'AddressSanitizer' +config.name = 'AddressSanitizer' + config.bits # Setup source root. config.test_source_root = os.path.dirname(__file__) def DisplayNoConfigMessage(): - lit.fatal("No site specific configuration available! " + - "Try running your test from the build tree or running " + - "make check-asan") + lit_config.fatal("No site specific configuration available! " + + "Try running your test from the build tree or running " + + "make check-asan") # Figure out LLVM source root. llvm_src_root = getattr(config, 'llvm_src_root', None) @@ -27,9 +30,9 @@ if llvm_src_root is None: # We probably haven't loaded the site-specific configuration: the user # is likely trying to run a test file directly, and the site configuration # wasn't created by the build system. - asan_site_cfg = lit.params.get('asan_site_config', None) + asan_site_cfg = lit_config.params.get('asan_site_config', None) if (asan_site_cfg) and (os.path.exists(asan_site_cfg)): - lit.load_config(config, asan_site_cfg) + lit_config.load_config(config, asan_site_cfg) raise SystemExit # Try to guess the location of site-specific configuration using llvm-config @@ -45,51 +48,45 @@ if llvm_src_root is None: if (not asan_site_cfg) or (not os.path.exists(asan_site_cfg)): DisplayNoConfigMessage() - lit.load_config(config, asan_site_cfg) + lit_config.load_config(config, asan_site_cfg) raise SystemExit -# Setup attributes common for all compiler-rt projects. -compiler_rt_src_root = get_required_attr(config, "compiler_rt_src_root") -compiler_rt_lit_cfg = os.path.join(compiler_rt_src_root, "lib", - "lit.common.cfg") -if (not compiler_rt_lit_cfg) or (not os.path.exists(compiler_rt_lit_cfg)): - lit.fatal("Can't find common compiler-rt lit config at: %r" - % compiler_rt_lit_cfg) -lit.load_config(config, compiler_rt_lit_cfg) - # Setup default compiler flags used with -fsanitize=address option. # FIXME: Review the set of required flags and check if it can be reduced. -clang_asan_cxxflags = ("-ccc-cxx " - + "-fsanitize=address " - + "-mno-omit-leaf-frame-pointer " - + "-fno-omit-frame-pointer " - + "-fno-optimize-sibling-calls " - + "-g") +bits_cflag = " -m" + config.bits +clang_asan_cflags = (" -fsanitize=address" + + " -mno-omit-leaf-frame-pointer" + + " -fno-omit-frame-pointer" + + " -fno-optimize-sibling-calls" + + " -g" + + bits_cflag) +clang_asan_cxxflags = " --driver-mode=g++" + clang_asan_cflags +config.substitutions.append( ("%clang ", " " + config.clang + bits_cflag + " ")) +config.substitutions.append( ("%clangxx ", (" " + config.clang + + " --driver-mode=g++" + + bits_cflag + " ")) ) +config.substitutions.append( ("%clang_asan ", (" " + config.clang + " " + + clang_asan_cflags + " ")) ) config.substitutions.append( ("%clangxx_asan ", (" " + config.clang + " " + clang_asan_cxxflags + " ")) ) -# Setup path to external LLVM symbolizer to run AddressSanitizer output tests. -llvm_tools_dir = getattr(config, 'llvm_tools_dir', None) -if llvm_tools_dir: - config.environment['LLVM_SYMBOLIZER_PATH'] = os.path.join( - llvm_tools_dir, "llvm-symbolizer") - -# Setup path to symbolizer script. -# FIXME: Instead we should copy this script to the build tree and point -# at it there. -asan_source_dir = os.path.join(config.test_source_root, "..") -symbolizer = os.path.join(asan_source_dir, - 'scripts', 'asan_symbolize.py') -if not os.path.exists(symbolizer): - lit.fatal("Can't find symbolizer script on path %r" % symbolizer) -# Define %symbolize substitution that filters output through -# symbolizer and c++filt (for demangling). -config.substitutions.append( ("%symbolize ", (" " + symbolizer + - " | c++filt " ))) +# Setup path to asan_symbolize.py script. +asan_source_dir = get_required_attr(config, "asan_source_dir") +asan_symbolize = os.path.join(asan_source_dir, "scripts", "asan_symbolize.py") +if not os.path.exists(asan_symbolize): + lit_config.fatal("Can't find script on path %r" % asan_symbolize) +python_exec = get_required_attr(config, "python_executable") +config.substitutions.append( ("%asan_symbolize", python_exec + " " + asan_symbolize + " ") ) # Define CHECK-%os to check for OS-dependent output. config.substitutions.append( ('CHECK-%os', ("CHECK-" + config.host_os))) +config.available_features.add("asan-" + config.bits + "-bits") + +# Turn on leak detection on 64-bit Linux. +if config.host_os == 'Linux' and config.bits == '64': + config.environment['ASAN_OPTIONS'] = 'detect_leaks=1' + # Default test suffixes. config.suffixes = ['.c', '.cc', '.cpp'] diff --git a/lib/asan/lit_tests/lit.site.cfg.in b/lib/asan/lit_tests/lit.site.cfg.in deleted file mode 100644 index 08546cdabe02..000000000000 --- a/lib/asan/lit_tests/lit.site.cfg.in +++ /dev/null @@ -1,22 +0,0 @@ -## Autogenerated by LLVM/Clang configuration. -# Do not edit! - -config.target_triple = "@TARGET_TRIPLE@" -config.host_os = "@HOST_OS@" -config.llvm_src_root = "@LLVM_SOURCE_DIR@" -config.llvm_obj_root = "@LLVM_BINARY_DIR@" -config.compiler_rt_src_root = "@COMPILER_RT_SOURCE_DIR@" -config.llvm_tools_dir = "@LLVM_TOOLS_DIR@" -config.clang = "@LLVM_BINARY_DIR@/bin/clang" -config.compiler_rt_arch = "@COMPILER_RT_SUPPORTED_ARCH@" - -# LLVM tools dir can be passed in lit parameters, so try to -# apply substitution. -try: - config.llvm_tools_dir = config.llvm_tools_dir % lit.params -except KeyError,e: - key, = e.args - lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key)) - -# Let the main config do the real work. -lit.load_config(config, "@ASAN_SOURCE_DIR@/lit_tests/lit.cfg") diff --git a/lib/asan/lit_tests/log-path_test.cc b/lib/asan/lit_tests/log-path_test.cc deleted file mode 100644 index 1072670fbff4..000000000000 --- a/lib/asan/lit_tests/log-path_test.cc +++ /dev/null @@ -1,39 +0,0 @@ -// RUN: %clangxx_asan %s -o %t - -// Regular run. -// RUN: not %t 2> %t.out -// RUN: FileCheck %s --check-prefix=CHECK-ERROR < %t.out - -// Good log_path. -// RUN: rm -f %t.log.* -// RUN: ASAN_OPTIONS=log_path=%t.log not %t 2> %t.out -// RUN: FileCheck %s --check-prefix=CHECK-ERROR < %t.log.* - -// Invalid log_path. -// RUN: ASAN_OPTIONS=log_path=/INVALID not %t 2> %t.out -// RUN: FileCheck %s --check-prefix=CHECK-INVALID < %t.out - -// Too long log_path. -// RUN: ASAN_OPTIONS=log_path=`for((i=0;i<10000;i++)); do echo -n $i; done` \ -// RUN: not %t 2> %t.out -// RUN: FileCheck %s --check-prefix=CHECK-LONG < %t.out - -// Run w/o errors should not produce any log. -// RUN: rm -f %t.log.* -// RUN: ASAN_OPTIONS=log_path=%t.log %t ARG ARG ARG -// RUN: not cat %t.log.* - - -#include -#include -int main(int argc, char **argv) { - if (argc > 2) return 0; - char *x = (char*)malloc(10); - memset(x, 0, 10); - int res = x[argc * 10]; // BOOOM - free(x); - return res; -} -// CHECK-ERROR: ERROR: AddressSanitizer -// CHECK-INVALID: ERROR: Can't open file: /INVALID -// CHECK-LONG: ERROR: Path is too long: 01234 diff --git a/lib/asan/lit_tests/log_path_fork_test.cc.disabled b/lib/asan/lit_tests/log_path_fork_test.cc.disabled deleted file mode 100644 index c6c1b49e994d..000000000000 --- a/lib/asan/lit_tests/log_path_fork_test.cc.disabled +++ /dev/null @@ -1,22 +0,0 @@ -// RUN: %clangxx_asan %s -o %t -// RUN: rm -f %t.log.* -// Set verbosity to 1 so that the log files are opened prior to fork(). -// RUN: ASAN_OPTIONS="log_path=%t.log verbosity=1" not %t 2> %t.out -// RUN: for f in %t.log.* ; do FileCheck %s < $f; done -// RUN: [ `ls %t.log.* | wc -l` == 2 ] - -#include -#include -#include - -int main(int argc, char **argv) { - void *x = malloc(10); - free(x); - if (fork() == -1) return 1; - // There are two processes at this point, thus there should be two distinct - // error logs. - free(x); - return 0; -} - -// CHECK: ERROR: AddressSanitizer diff --git a/lib/asan/lit_tests/malloc_fill.cc b/lib/asan/lit_tests/malloc_fill.cc deleted file mode 100644 index c23516b33299..000000000000 --- a/lib/asan/lit_tests/malloc_fill.cc +++ /dev/null @@ -1,22 +0,0 @@ -// Check that we fill malloc-ed memory correctly. -// RUN: %clangxx_asan -m64 %s -o %t -// RUN: %t | FileCheck %s -// RUN: ASAN_OPTIONS=max_malloc_fill_size=10:malloc_fill_byte=8 %t | FileCheck %s --check-prefix=CHECK-10-8 -// RUN: ASAN_OPTIONS=max_malloc_fill_size=20:malloc_fill_byte=171 %t | FileCheck %s --check-prefix=CHECK-20-ab - -#include -int main(int argc, char **argv) { - // With asan allocator this makes sure we get memory from mmap. - static const int kSize = 1 << 25; - unsigned char *x = new unsigned char[kSize]; - printf("-"); - for (int i = 0; i <= 32; i++) { - printf("%02x", x[i]); - } - printf("-\n"); - delete [] x; -} - -// CHECK: -bebebebebebebebebebebebebebebebebebebebebebebebebebebebebebebebebe- -// CHECK-10-8: -080808080808080808080000000000000000000000000000000000000000000000- -// CHECK-20-ab: -abababababababababababababababababababab00000000000000000000000000- diff --git a/lib/asan/lit_tests/malloc_hook.cc b/lib/asan/lit_tests/malloc_hook.cc deleted file mode 100644 index 6435d105ee26..000000000000 --- a/lib/asan/lit_tests/malloc_hook.cc +++ /dev/null @@ -1,24 +0,0 @@ -// RUN: %clangxx_asan -O2 %s -o %t -// RUN: %t 2>&1 | FileCheck %s -#include -#include - -extern "C" { -// Note: avoid calling functions that allocate memory in malloc/free -// to avoid infinite recursion. -void __asan_malloc_hook(void *ptr, size_t sz) { - write(1, "MallocHook\n", sizeof("MallocHook\n")); -} -void __asan_free_hook(void *ptr) { - write(1, "FreeHook\n", sizeof("FreeHook\n")); -} -} // extern "C" - -int main() { - volatile int *x = new int; - // CHECK: MallocHook - *x = 0; - delete x; - // CHECK: FreeHook - return 0; -} diff --git a/lib/asan/lit_tests/memcmp_strict_test.cc b/lib/asan/lit_tests/memcmp_strict_test.cc deleted file mode 100644 index 00bf921c744a..000000000000 --- a/lib/asan/lit_tests/memcmp_strict_test.cc +++ /dev/null @@ -1,16 +0,0 @@ -// RUN: %clangxx_asan -m64 -O0 %s -o %t && ASAN_OPTIONS=strict_memcmp=0 %t 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK-nonstrict -// RUN: %clangxx_asan -m64 -O0 %s -o %t && ASAN_OPTIONS=strict_memcmp=1 %t 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK-strict -// Default to strict_memcmp=1. -// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK-strict - -#include -#include -int main() { - char kFoo[] = "foo"; - char kFubar[] = "fubar"; - int res = memcmp(kFoo, kFubar, strlen(kFubar)); - printf("res: %d\n", res); - // CHECK-nonstrict: {{res: -1}} - // CHECK-strict: AddressSanitizer: stack-buffer-overflow - return 0; -} diff --git a/lib/asan/lit_tests/memcmp_test.cc b/lib/asan/lit_tests/memcmp_test.cc deleted file mode 100644 index ac3f7f32ea75..000000000000 --- a/lib/asan/lit_tests/memcmp_test.cc +++ /dev/null @@ -1,19 +0,0 @@ -// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s - -#include -int main(int argc, char **argv) { - char a1[] = {argc, 2, 3, 4}; - char a2[] = {1, 2*argc, 3, 4}; - int res = memcmp(a1, a2, 4 + argc); // BOOM - // CHECK: AddressSanitizer: stack-buffer-overflow - // CHECK: {{#0.*memcmp}} - // CHECK: {{#1.*main}} - return res; -} diff --git a/lib/asan/lit_tests/null_deref.cc b/lib/asan/lit_tests/null_deref.cc deleted file mode 100644 index 60a521d1c210..000000000000 --- a/lib/asan/lit_tests/null_deref.cc +++ /dev/null @@ -1,31 +0,0 @@ -// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out - -__attribute__((noinline)) -static void NullDeref(int *ptr) { - // CHECK: ERROR: AddressSanitizer: SEGV on unknown address - // CHECK: {{0x0*00028 .*pc 0x.*}} - // CHECK: {{AddressSanitizer can not provide additional info.}} - ptr[10]++; // BOOM - // atos on Mac cannot extract the symbol name correctly. - // CHECK-Linux: {{ #0 0x.* in NullDeref.*null_deref.cc:}}[[@LINE-2]] - // CHECK-Darwin: {{ #0 0x.* in .*NullDeref.*null_deref.cc:}}[[@LINE-3]] -} -int main() { - NullDeref((int*)0); - // CHECK: {{ #1 0x.* in _?main.*null_deref.cc:}}[[@LINE-1]] -} diff --git a/lib/asan/lit_tests/on_error_callback.cc b/lib/asan/lit_tests/on_error_callback.cc deleted file mode 100644 index bb94d9fb579b..000000000000 --- a/lib/asan/lit_tests/on_error_callback.cc +++ /dev/null @@ -1,16 +0,0 @@ -// RUN: %clangxx_asan -O2 %s -o %t && %t 2>&1 | FileCheck %s - -#include -#include - -extern "C" -void __asan_on_error() { - fprintf(stderr, "__asan_on_error called"); -} - -int main() { - char *x = (char*)malloc(10 * sizeof(char)); - free(x); - return x[5]; - // CHECK: __asan_on_error called -} diff --git a/lib/asan/lit_tests/partial_right.cc b/lib/asan/lit_tests/partial_right.cc deleted file mode 100644 index c579262726f9..000000000000 --- a/lib/asan/lit_tests/partial_right.cc +++ /dev/null @@ -1,17 +0,0 @@ -// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s - -#include -int main(int argc, char **argv) { - volatile int *x = (int*)malloc(2*sizeof(int) + 2); - int res = x[2]; // BOOOM - // CHECK: {{READ of size 4 at 0x.* thread T0}} - // CHECK: [[ADDR:0x[01-9a-fa-f]+]] is located 0 bytes to the right of {{.*}}-byte region [{{.*}},{{.*}}[[ADDR]]) - return res; -} diff --git a/lib/asan/lit_tests/sanity_check_pure_c.c b/lib/asan/lit_tests/sanity_check_pure_c.c deleted file mode 100644 index 3d830653e33e..000000000000 --- a/lib/asan/lit_tests/sanity_check_pure_c.c +++ /dev/null @@ -1,19 +0,0 @@ -// Sanity checking a test in pure C. -// RUN: %clang -g -fsanitize=address -O2 %s -o %t -// RUN: %t 2>&1 | %symbolize | FileCheck %s - -// Sanity checking a test in pure C with -pie. -// RUN: %clang -g -fsanitize=address -O2 %s -pie -o %t -// RUN: %t 2>&1 | %symbolize | FileCheck %s - -#include -int main() { - char *x = (char*)malloc(10 * sizeof(char)); - free(x); - return x[5]; - // CHECK: heap-use-after-free - // CHECK: free - // CHECK: main{{.*}}sanity_check_pure_c.c:[[@LINE-4]] - // CHECK: malloc - // CHECK: main{{.*}}sanity_check_pure_c.c:[[@LINE-7]] -} diff --git a/lib/asan/lit_tests/shared-lib-test.cc b/lib/asan/lit_tests/shared-lib-test.cc deleted file mode 100644 index 05bf3ecdf4f9..000000000000 --- a/lib/asan/lit_tests/shared-lib-test.cc +++ /dev/null @@ -1,54 +0,0 @@ -// RUN: %clangxx_asan -m64 -O0 %p/SharedLibs/shared-lib-test-so.cc \ -// RUN: -fPIC -shared -o %t-so.so -// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m64 -O1 %p/SharedLibs/shared-lib-test-so.cc \ -// RUN: -fPIC -shared -o %t-so.so -// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m64 -O2 %p/SharedLibs/shared-lib-test-so.cc \ -// RUN: -fPIC -shared -o %t-so.so -// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m64 -O3 %p/SharedLibs/shared-lib-test-so.cc \ -// RUN: -fPIC -shared -o %t-so.so -// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O0 %p/SharedLibs/shared-lib-test-so.cc \ -// RUN: -fPIC -shared -o %t-so.so -// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O1 %p/SharedLibs/shared-lib-test-so.cc \ -// RUN: -fPIC -shared -o %t-so.so -// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O2 %p/SharedLibs/shared-lib-test-so.cc \ -// RUN: -fPIC -shared -o %t-so.so -// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O3 %p/SharedLibs/shared-lib-test-so.cc \ -// RUN: -fPIC -shared -o %t-so.so -// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s - -#include -#include -#include - -#include - -using std::string; - -typedef void (fun_t)(int x); - -int main(int argc, char *argv[]) { - string path = string(argv[0]) + "-so.so"; - printf("opening %s ... \n", path.c_str()); - void *lib = dlopen(path.c_str(), RTLD_NOW); - if (!lib) { - printf("error in dlopen(): %s\n", dlerror()); - return 1; - } - fun_t *inc = (fun_t*)dlsym(lib, "inc"); - if (!inc) return 1; - printf("ok\n"); - inc(1); - inc(-1); // BOOM - // CHECK: {{.*ERROR: AddressSanitizer: global-buffer-overflow}} - // CHECK: {{READ of size 4 at 0x.* thread T0}} - // CHECK: {{ #0 0x.*}} - // CHECK: {{ #1 0x.* in _?main .*shared-lib-test.cc:}}[[@LINE-4]] - return 0; -} diff --git a/lib/asan/lit_tests/sleep_before_dying.c b/lib/asan/lit_tests/sleep_before_dying.c deleted file mode 100644 index df9eba276039..000000000000 --- a/lib/asan/lit_tests/sleep_before_dying.c +++ /dev/null @@ -1,10 +0,0 @@ -// RUN: %clang -g -fsanitize=address -O2 %s -o %t -// RUN: ASAN_OPTIONS="sleep_before_dying=1" %t 2>&1 | FileCheck %s - -#include -int main() { - char *x = (char*)malloc(10 * sizeof(char)); - free(x); - return x[5]; - // CHECK: Sleeping for 1 second -} diff --git a/lib/asan/lit_tests/stack-frame-demangle.cc b/lib/asan/lit_tests/stack-frame-demangle.cc deleted file mode 100644 index bb8de16b2b8a..000000000000 --- a/lib/asan/lit_tests/stack-frame-demangle.cc +++ /dev/null @@ -1,22 +0,0 @@ -// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s - -#include - -namespace XXX { -struct YYY { - static int ZZZ(int x) { - char array[10]; - memset(array, 0, 10); - return array[x]; // BOOOM - // CHECK: ERROR: AddressSanitizer: stack-buffer-overflow - // CHECK: READ of size 1 at - // CHECK: is located in stack of thread T0 at offset - // CHECK: XXX::YYY::ZZZ - } -}; -} // namespace XXX - -int main(int argc, char **argv) { - int res = XXX::YYY::ZZZ(argc + 10); - return res; -} diff --git a/lib/asan/lit_tests/stack-oob-frames.cc b/lib/asan/lit_tests/stack-oob-frames.cc deleted file mode 100644 index 0395522252e8..000000000000 --- a/lib/asan/lit_tests/stack-oob-frames.cc +++ /dev/null @@ -1,59 +0,0 @@ -// RUN: %clangxx_asan -m64 -O1 %s -o %t -// RUN: %t 0 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK0 -// RUN: %t 1 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK1 -// RUN: %t 2 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK2 -// RUN: %t 3 2>&1 | %symbolize | FileCheck %s --check-prefix=CHECK3 - -#define NOINLINE __attribute__((noinline)) -inline void break_optimization(void *arg) { - __asm__ __volatile__("" : : "r" (arg) : "memory"); -} - -NOINLINE static void Frame0(int frame, char *a, char *b, char *c) { - char s[4] = {0}; - char *d = s; - break_optimization(&d); - switch (frame) { - case 3: a[5]++; break; - case 2: b[5]++; break; - case 1: c[5]++; break; - case 0: d[5]++; break; - } -} -NOINLINE static void Frame1(int frame, char *a, char *b) { - char c[4] = {0}; Frame0(frame, a, b, c); - break_optimization(0); -} -NOINLINE static void Frame2(int frame, char *a) { - char b[4] = {0}; Frame1(frame, a, b); - break_optimization(0); -} -NOINLINE static void Frame3(int frame) { - char a[4] = {0}; Frame2(frame, a); - break_optimization(0); -} - -int main(int argc, char **argv) { - if (argc != 2) return 1; - Frame3(argv[1][0] - '0'); -} - -// CHECK0: AddressSanitizer: stack-buffer-overflow -// CHECK0: #0{{.*}}Frame0 -// CHECK0: #1{{.*}}Frame1 -// CHECK0: #2{{.*}}Frame2 -// CHECK0: #3{{.*}}Frame3 -// CHECK0: is located in stack of thread T0 at offset -// CHECK0-NEXT: #0{{.*}}Frame0 -// -// CHECK1: AddressSanitizer: stack-buffer-overflow -// CHECK1: is located in stack of thread T0 at offset -// CHECK1-NEXT: #0{{.*}}Frame1 -// -// CHECK2: AddressSanitizer: stack-buffer-overflow -// CHECK2: is located in stack of thread T0 at offset -// CHECK2-NEXT: #0{{.*}}Frame2 -// -// CHECK3: AddressSanitizer: stack-buffer-overflow -// CHECK3: is located in stack of thread T0 at offset -// CHECK3-NEXT: #0{{.*}}Frame3 diff --git a/lib/asan/lit_tests/stack-overflow.cc b/lib/asan/lit_tests/stack-overflow.cc deleted file mode 100644 index 25ea43af48a4..000000000000 --- a/lib/asan/lit_tests/stack-overflow.cc +++ /dev/null @@ -1,20 +0,0 @@ -// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s - -#include -int main(int argc, char **argv) { - char x[10]; - memset(x, 0, 10); - int res = x[argc * 10]; // BOOOM - // CHECK: {{READ of size 1 at 0x.* thread T0}} - // CHECK: {{ #0 0x.* in _?main .*stack-overflow.cc:}}[[@LINE-2]] - // CHECK: {{Address 0x.* is located in stack of thread T0 at offset}} - // CHECK-NEXT: in{{.*}}main{{.*}}stack-overflow.cc - return res; -} diff --git a/lib/asan/lit_tests/stack-use-after-return.cc b/lib/asan/lit_tests/stack-use-after-return.cc deleted file mode 100644 index f8d8a1a2ae39..000000000000 --- a/lib/asan/lit_tests/stack-use-after-return.cc +++ /dev/null @@ -1,45 +0,0 @@ -// XFAIL: * -// RUN: %clangxx_asan -fsanitize=use-after-return -m64 -O0 %s -o %t && \ -// RUN: %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -fsanitize=use-after-return -m64 -O1 %s -o %t && \ -// RUN: %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -fsanitize=use-after-return -m64 -O2 %s -o %t && \ -// RUN: %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -fsanitize=use-after-return -m64 -O3 %s -o %t && \ -// RUN: %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -fsanitize=use-after-return -m32 -O0 %s -o %t && \ -// RUN: %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -fsanitize=use-after-return -m32 -O1 %s -o %t && \ -// RUN: %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -fsanitize=use-after-return -m32 -O2 %s -o %t && \ -// RUN: %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -fsanitize=use-after-return -m32 -O3 %s -o %t && \ -// RUN: %t 2>&1 | %symbolize | FileCheck %s - -#include - -__attribute__((noinline)) -char *Ident(char *x) { - fprintf(stderr, "1: %p\n", x); - return x; -} - -__attribute__((noinline)) -char *Func1() { - char local; - return Ident(&local); -} - -__attribute__((noinline)) -void Func2(char *x) { - fprintf(stderr, "2: %p\n", x); - *x = 1; - // CHECK: WRITE of size 1 {{.*}} thread T0 - // CHECK: #0{{.*}}Func2{{.*}}stack-use-after-return.cc:[[@LINE-2]] - // CHECK: is located {{.*}} in frame <{{.*}}Func1{{.*}}> of T0's stack -} - -int main(int argc, char **argv) { - Func2(Func1()); - return 0; -} diff --git a/lib/asan/lit_tests/strip_path_prefix.c b/lib/asan/lit_tests/strip_path_prefix.c deleted file mode 100644 index ef7bf98ab3c2..000000000000 --- a/lib/asan/lit_tests/strip_path_prefix.c +++ /dev/null @@ -1,12 +0,0 @@ -// RUN: %clang -g -fsanitize=address -O2 %s -o %t -// RUN: ASAN_OPTIONS="strip_path_prefix='/'" %t 2>&1 | FileCheck %s - -#include -int main() { - char *x = (char*)malloc(10 * sizeof(char)); - free(x); - return x[5]; - // Check that paths in error report don't start with slash. - // CHECK: heap-use-after-free - // CHECK-NOT: #0 0x{{.*}} ({{[/].*}}) -} diff --git a/lib/asan/lit_tests/strncpy-overflow.cc b/lib/asan/lit_tests/strncpy-overflow.cc deleted file mode 100644 index 5133b5c1653e..000000000000 --- a/lib/asan/lit_tests/strncpy-overflow.cc +++ /dev/null @@ -1,38 +0,0 @@ -// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out - -#include -#include -int main(int argc, char **argv) { - char *hello = (char*)malloc(6); - strcpy(hello, "hello"); - char *short_buffer = (char*)malloc(9); - strncpy(short_buffer, hello, 10); // BOOM - // CHECK: {{WRITE of size 10 at 0x.* thread T0}} - // CHECK-Linux: {{ #0 0x.* in .*strncpy}} - // CHECK-Darwin: {{ #0 0x.* in _?wrap_strncpy}} - // CHECK: {{ #1 0x.* in _?main .*strncpy-overflow.cc:}}[[@LINE-4]] - // CHECK: {{0x.* is located 0 bytes to the right of 9-byte region}} - // CHECK: {{allocated by thread T0 here:}} - - // CHECK-Linux: {{ #0 0x.* in .*malloc}} - // CHECK-Linux: {{ #1 0x.* in main .*strncpy-overflow.cc:}}[[@LINE-10]] - - // CHECK-Darwin: {{ #0 0x.* in _?wrap_malloc.*}} - // CHECK-Darwin: {{ #1 0x.* in _?main .*strncpy-overflow.cc:}}[[@LINE-13]] - return short_buffer[8]; -} diff --git a/lib/asan/lit_tests/symbolize_callback.cc b/lib/asan/lit_tests/symbolize_callback.cc deleted file mode 100644 index 0691d501e24d..000000000000 --- a/lib/asan/lit_tests/symbolize_callback.cc +++ /dev/null @@ -1,17 +0,0 @@ -// RUN: %clangxx_asan -O2 %s -o %t && %t 2>&1 | FileCheck %s - -#include -#include - -extern "C" -bool __asan_symbolize(const void *pc, char *out_buffer, int out_size) { - snprintf(out_buffer, out_size, "MySymbolizer"); - return true; -} - -int main() { - char *x = (char*)malloc(10 * sizeof(char)); - free(x); - return x[5]; - // CHECK: MySymbolizer -} diff --git a/lib/asan/lit_tests/throw_call_test.cc b/lib/asan/lit_tests/throw_call_test.cc deleted file mode 100644 index 974bc51d97c5..000000000000 --- a/lib/asan/lit_tests/throw_call_test.cc +++ /dev/null @@ -1,45 +0,0 @@ -// RUN: %clangxx_asan %s -o %t && %t -// http://code.google.com/p/address-sanitizer/issues/detail?id=147 (not fixed). -// BROKEN: %clangxx_asan %s -o %t -static-libstdc++ && %t -#include -static volatile int zero = 0; -inline void pretend_to_do_something(void *x) { - __asm__ __volatile__("" : : "r" (x) : "memory"); -} - -__attribute__((noinline, no_sanitize_address)) -void ReallyThrow() { - fprintf(stderr, "ReallyThrow\n"); - if (zero == 0) - throw 42; -} - -__attribute__((noinline)) -void Throw() { - int a, b, c, d, e; - pretend_to_do_something(&a); - pretend_to_do_something(&b); - pretend_to_do_something(&c); - pretend_to_do_something(&d); - pretend_to_do_something(&e); - fprintf(stderr, "Throw stack = %p\n", &a); - ReallyThrow(); -} - -__attribute__((noinline)) -void CheckStack() { - int ar[100]; - pretend_to_do_something(ar); - for (int i = 0; i < 100; i++) - ar[i] = i; - fprintf(stderr, "CheckStack stack = %p, %p\n", ar, ar + 100); -} - -int main(int argc, char** argv) { - try { - Throw(); - } catch(int a) { - fprintf(stderr, "a = %d\n", a); - } - CheckStack(); -} diff --git a/lib/asan/lit_tests/throw_invoke_test.cc b/lib/asan/lit_tests/throw_invoke_test.cc deleted file mode 100644 index 077a940e8d19..000000000000 --- a/lib/asan/lit_tests/throw_invoke_test.cc +++ /dev/null @@ -1,50 +0,0 @@ -// RUN: %clangxx_asan %s -o %t && %t -// RUN: %clangxx_asan %s -o %t -static-libstdc++ && %t -#include -static volatile int zero = 0; -inline void pretend_to_do_something(void *x) { - __asm__ __volatile__("" : : "r" (x) : "memory"); -} - -__attribute__((noinline)) -void ReallyThrow() { - fprintf(stderr, "ReallyThrow\n"); - try { - if (zero == 0) - throw 42; - else if (zero == 1) - throw 1.; - } catch(double x) { - } -} - -__attribute__((noinline)) -void Throw() { - int a, b, c, d, e; - pretend_to_do_something(&a); - pretend_to_do_something(&b); - pretend_to_do_something(&c); - pretend_to_do_something(&d); - pretend_to_do_something(&e); - fprintf(stderr, "Throw stack = %p\n", &a); - ReallyThrow(); -} - -__attribute__((noinline)) -void CheckStack() { - int ar[100]; - pretend_to_do_something(ar); - for (int i = 0; i < 100; i++) - ar[i] = i; - fprintf(stderr, "CheckStack stack = %p, %p\n", ar, ar + 100); -} - -int main(int argc, char** argv) { - try { - Throw(); - } catch(int a) { - fprintf(stderr, "a = %d\n", a); - } - CheckStack(); -} - diff --git a/lib/asan/lit_tests/time_interceptor.cc b/lib/asan/lit_tests/time_interceptor.cc deleted file mode 100644 index f5f2ad62b815..000000000000 --- a/lib/asan/lit_tests/time_interceptor.cc +++ /dev/null @@ -1,16 +0,0 @@ -// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s - -// Test the time() interceptor. - -#include -#include -#include - -int main() { - time_t *tm = (time_t*)malloc(sizeof(time_t)); - free(tm); - time_t t = time(tm); - printf("Time: %s\n", ctime(&t)); // NOLINT - // CHECK: use-after-free - return 0; -} diff --git a/lib/asan/lit_tests/unaligned_loads_and_stores.cc b/lib/asan/lit_tests/unaligned_loads_and_stores.cc deleted file mode 100644 index bcae089b427b..000000000000 --- a/lib/asan/lit_tests/unaligned_loads_and_stores.cc +++ /dev/null @@ -1,52 +0,0 @@ -// RUN: %clangxx_asan -O0 -I %p/../../../include %s -o %t -// RUN: %t A 2>&1 | %symbolize | FileCheck --check-prefix=CHECK-A %s -// RUN: %t B 2>&1 | %symbolize | FileCheck --check-prefix=CHECK-B %s -// RUN: %t C 2>&1 | %symbolize | FileCheck --check-prefix=CHECK-C %s -// RUN: %t D 2>&1 | %symbolize | FileCheck --check-prefix=CHECK-D %s -// RUN: %t E 2>&1 | %symbolize | FileCheck --check-prefix=CHECK-E %s - -// RUN: %t K 2>&1 | %symbolize | FileCheck --check-prefix=CHECK-K %s -// RUN: %t L 2>&1 | %symbolize | FileCheck --check-prefix=CHECK-L %s -// RUN: %t M 2>&1 | %symbolize | FileCheck --check-prefix=CHECK-M %s -// RUN: %t N 2>&1 | %symbolize | FileCheck --check-prefix=CHECK-N %s -// RUN: %t O 2>&1 | %symbolize | FileCheck --check-prefix=CHECK-O %s - -#include - -#include -#include -int main(int argc, char **argv) { - if (argc != 2) return 1; - char *x = new char[16]; - memset(x, 0xab, 16); - int res = 1; - switch (argv[1][0]) { - case 'A': res = __sanitizer_unaligned_load16(x + 15); break; -// CHECK-A ERROR: AddressSanitizer: heap-buffer-overflow on address -// CHECK-A: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-2]] -// CHECK-A: is located 0 bytes to the right of 16-byte region - case 'B': res = __sanitizer_unaligned_load32(x + 14); break; -// CHECK-B: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]] - case 'C': res = __sanitizer_unaligned_load32(x + 13); break; -// CHECK-C: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]] - case 'D': res = __sanitizer_unaligned_load64(x + 15); break; -// CHECK-D: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]] - case 'E': res = __sanitizer_unaligned_load64(x + 9); break; -// CHECK-E: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]] - - case 'K': __sanitizer_unaligned_store16(x + 15, 0); break; -// CHECK-K ERROR: AddressSanitizer: heap-buffer-overflow on address -// CHECK-K: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-2]] -// CHECK-K: is located 0 bytes to the right of 16-byte region - case 'L': __sanitizer_unaligned_store32(x + 15, 0); break; -// CHECK-L: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]] - case 'M': __sanitizer_unaligned_store32(x + 13, 0); break; -// CHECK-M: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]] - case 'N': __sanitizer_unaligned_store64(x + 10, 0); break; -// CHECK-N: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]] - case 'O': __sanitizer_unaligned_store64(x + 14, 0); break; -// CHECK-O: main{{.*}}unaligned_loads_and_stores.cc:[[@LINE-1]] - } - delete x; - return res; -} diff --git a/lib/asan/lit_tests/use-after-free-right.cc b/lib/asan/lit_tests/use-after-free-right.cc deleted file mode 100644 index b0de07b04a08..000000000000 --- a/lib/asan/lit_tests/use-after-free-right.cc +++ /dev/null @@ -1,46 +0,0 @@ -// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out - -// Test use-after-free report in the case when access is at the right border of -// the allocation. - -#include -int main() { - volatile char *x = (char*)malloc(sizeof(char)); - free((void*)x); - *x = 42; - // CHECK: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}} - // CHECK: {{0x.* at pc 0x.* bp 0x.* sp 0x.*}} - // CHECK: {{WRITE of size 1 at 0x.* thread T0}} - // CHECK: {{ #0 0x.* in _?main .*use-after-free-right.cc:25}} - // CHECK: {{0x.* is located 0 bytes inside of 1-byte region .0x.*,0x.*}} - // CHECK: {{freed by thread T0 here:}} - - // CHECK-Linux: {{ #0 0x.* in .*free}} - // CHECK-Linux: {{ #1 0x.* in main .*use-after-free-right.cc:24}} - - // CHECK-Darwin: {{ #0 0x.* in _?wrap_free}} - // CHECK-Darwin: {{ #1 0x.* in _?main .*use-after-free-right.cc:24}} - - // CHECK: {{previously allocated by thread T0 here:}} - - // CHECK-Linux: {{ #0 0x.* in .*malloc}} - // CHECK-Linux: {{ #1 0x.* in main .*use-after-free-right.cc:23}} - - // CHECK-Darwin: {{ #0 0x.* in _?wrap_malloc.*}} - // CHECK-Darwin: {{ #1 0x.* in _?main .*use-after-free-right.cc:23}} -} diff --git a/lib/asan/lit_tests/use-after-free.cc b/lib/asan/lit_tests/use-after-free.cc deleted file mode 100644 index aee185dc4518..000000000000 --- a/lib/asan/lit_tests/use-after-free.cc +++ /dev/null @@ -1,43 +0,0 @@ -// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out -// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out -// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out - -#include -int main() { - char *x = (char*)malloc(10 * sizeof(char)); - free(x); - return x[5]; - // CHECK: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}} - // CHECK: {{0x.* at pc 0x.* bp 0x.* sp 0x.*}} - // CHECK: {{READ of size 1 at 0x.* thread T0}} - // CHECK: {{ #0 0x.* in _?main .*use-after-free.cc:22}} - // CHECK: {{0x.* is located 5 bytes inside of 10-byte region .0x.*,0x.*}} - // CHECK: {{freed by thread T0 here:}} - - // CHECK-Linux: {{ #0 0x.* in .*free}} - // CHECK-Linux: {{ #1 0x.* in main .*use-after-free.cc:21}} - - // CHECK-Darwin: {{ #0 0x.* in _?wrap_free}} - // CHECK-Darwin: {{ #1 0x.* in _?main .*use-after-free.cc:21}} - - // CHECK: {{previously allocated by thread T0 here:}} - - // CHECK-Linux: {{ #0 0x.* in .*malloc}} - // CHECK-Linux: {{ #1 0x.* in main .*use-after-free.cc:20}} - - // CHECK-Darwin: {{ #0 0x.* in _?wrap_malloc.*}} - // CHECK-Darwin: {{ #1 0x.* in _?main .*use-after-free.cc:20}} -} diff --git a/lib/asan/lit_tests/use-after-poison.cc b/lib/asan/lit_tests/use-after-poison.cc deleted file mode 100644 index d87342900245..000000000000 --- a/lib/asan/lit_tests/use-after-poison.cc +++ /dev/null @@ -1,20 +0,0 @@ -// Check that __asan_poison_memory_region works. -// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// -// Check that we can disable it -// RUN: ASAN_OPTIONS=allow_user_poisoning=0 %t - -#include - -extern "C" void __asan_poison_memory_region(void *, size_t); - -int main(int argc, char **argv) { - char *x = new char[16]; - x[10] = 0; - __asan_poison_memory_region(x, 16); - int res = x[argc * 10]; // BOOOM - // CHECK: ERROR: AddressSanitizer: use-after-poison - // CHECK: main{{.*}}use-after-poison.cc:[[@LINE-2]] - delete [] x; - return res; -} diff --git a/lib/asan/lit_tests/use-after-scope-inlined.cc b/lib/asan/lit_tests/use-after-scope-inlined.cc deleted file mode 100644 index 5c121ea187eb..000000000000 --- a/lib/asan/lit_tests/use-after-scope-inlined.cc +++ /dev/null @@ -1,30 +0,0 @@ -// Test with "-O2" only to make sure inlining (leading to use-after-scope) -// happens. "always_inline" is not enough, as Clang doesn't emit -// llvm.lifetime intrinsics at -O0. -// -// RUN: %clangxx_asan -m64 -O2 -fsanitize=use-after-scope %s -o %t && \ -// RUN: %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -m32 -O2 -fsanitize=use-after-scope %s -o %t && \ -// RUN: %t 2>&1 | %symbolize | FileCheck %s - -int *arr; - -__attribute__((always_inline)) -void inlined(int arg) { - int x[5]; - for (int i = 0; i < arg; i++) x[i] = i; - arr = x; -} - -int main(int argc, char *argv[]) { - inlined(argc); - return arr[argc - 1]; // BOOM - // CHECK: ERROR: AddressSanitizer: stack-use-after-scope - // CHECK: READ of size 4 at 0x{{.*}} thread T0 - // CHECK: #0 0x{{.*}} in {{_?}}main - // CHECK: {{.*}}use-after-scope-inlined.cc:[[@LINE-4]] - // CHECK: Address 0x{{.*}} is located in stack of thread T0 at offset - // CHECK: [[OFFSET:[^ ]*]] in frame - // CHECK: main - // CHECK: {{\[}}[[OFFSET]], {{.*}}) 'x.i' -} diff --git a/lib/asan/lit_tests/wait.cc b/lib/asan/lit_tests/wait.cc deleted file mode 100644 index 88fbb17176fa..000000000000 --- a/lib/asan/lit_tests/wait.cc +++ /dev/null @@ -1,77 +0,0 @@ -// RUN: %clangxx_asan -DWAIT -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -DWAIT -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -DWAIT -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -DWAIT -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s - -// RUN: %clangxx_asan -DWAITPID -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -DWAITPID -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -DWAITPID -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -DWAITPID -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s - -// RUN: %clangxx_asan -DWAITID -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -DWAITID -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -DWAITID -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -DWAITID -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s - -// RUN: %clangxx_asan -DWAIT3 -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -DWAIT3 -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -DWAIT3 -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -DWAIT3 -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s - -// RUN: %clangxx_asan -DWAIT4 -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -DWAIT4 -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -DWAIT4 -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -DWAIT4 -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s - -// RUN: %clangxx_asan -DWAIT3_RUSAGE -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -DWAIT3_RUSAGE -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -DWAIT3_RUSAGE -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -DWAIT3_RUSAGE -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s - -// RUN: %clangxx_asan -DWAIT4_RUSAGE -m64 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -DWAIT4_RUSAGE -m64 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -DWAIT4_RUSAGE -m32 -O0 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s -// RUN: %clangxx_asan -DWAIT4_RUSAGE -m32 -O3 %s -o %t && %t 2>&1 | %symbolize | FileCheck %s - - -#include -#include -#include - -int main(int argc, char **argv) { - pid_t pid = fork(); - if (pid) { // parent - int x[3]; - int *status = x + argc * 3; - int res; -#if defined(WAIT) - res = wait(status); -#elif defined(WAITPID) - res = waitpid(pid, status, WNOHANG); -#elif defined(WAITID) - siginfo_t *si = (siginfo_t*)(x + argc * 3); - res = waitid(P_ALL, 0, si, WEXITED | WNOHANG); -#elif defined(WAIT3) - res = wait3(status, WNOHANG, NULL); -#elif defined(WAIT4) - res = wait4(pid, status, WNOHANG, NULL); -#elif defined(WAIT3_RUSAGE) || defined(WAIT4_RUSAGE) - struct rusage *ru = (struct rusage*)(x + argc * 3); - int good_status; -# if defined(WAIT3_RUSAGE) - res = wait3(&good_status, WNOHANG, ru); -# elif defined(WAIT4_RUSAGE) - res = wait4(pid, &good_status, WNOHANG, ru); -# endif -#endif - // CHECK: stack-buffer-overflow - // CHECK: {{WRITE of size .* at 0x.* thread T0}} - // CHECK: {{in .*wait}} - // CHECK: {{in _?main .*wait.cc:}} - // CHECK: is located in stack of thread T0 at offset - // CHECK: {{in _?main}} - return res != -1; - } - // child - return 0; -} diff --git a/lib/asan/scripts/asan_symbolize.py b/lib/asan/scripts/asan_symbolize.py index bd3bf1e9b53e..a398fcf10361 100755 --- a/lib/asan/scripts/asan_symbolize.py +++ b/lib/asan/scripts/asan_symbolize.py @@ -10,14 +10,14 @@ import bisect import getopt import os +import pty import re import subprocess import sys +import termios llvm_symbolizer = None symbolizers = {} -filetypes = {} -vmaddrs = {} DEBUG = False demangle = False; @@ -101,8 +101,10 @@ class LLVMSymbolizer(Symbolizer): def LLVMSymbolizerFactory(system): symbolizer_path = os.getenv('LLVM_SYMBOLIZER_PATH') if not symbolizer_path: - # Assume llvm-symbolizer is in PATH. - symbolizer_path = 'llvm-symbolizer' + symbolizer_path = os.getenv('ASAN_SYMBOLIZER_PATH') + if not symbolizer_path: + # Assume llvm-symbolizer is in PATH. + symbolizer_path = 'llvm-symbolizer' return LLVMSymbolizer(symbolizer_path) @@ -137,6 +139,36 @@ class Addr2LineSymbolizer(Symbolizer): return ['%s in %s %s' % (addr, function_name, file_name)] +class UnbufferedLineConverter(object): + """ + Wrap a child process that responds to each line of input with one line of + output. Uses pty to trick the child into providing unbuffered output. + """ + def __init__(self, args, close_stderr=False): + pid, fd = pty.fork() + if pid == 0: + # We're the child. Transfer control to command. + if close_stderr: + dev_null = os.open('/dev/null', 0) + os.dup2(dev_null, 2) + os.execvp(args[0], args) + else: + # Disable echoing. + attr = termios.tcgetattr(fd) + attr[3] = attr[3] & ~termios.ECHO + termios.tcsetattr(fd, termios.TCSANOW, attr) + # Set up a file()-like interface to the child process + self.r = os.fdopen(fd, "r", 1) + self.w = os.fdopen(os.dup(fd), "w", 1) + + def convert(self, line): + self.w.write(line + "\n") + return self.readline() + + def readline(self): + return self.r.readline().rstrip() + + class DarwinSymbolizer(Symbolizer): def __init__(self, addr, binary): super(DarwinSymbolizer, self).__init__() @@ -146,29 +178,21 @@ class DarwinSymbolizer(Symbolizer): self.arch = 'x86_64' else: self.arch = 'i386' - self.vmaddr = None - self.pipe = None - - def write_addr_to_pipe(self, offset): - print >> self.pipe.stdin, '0x%x' % int(offset, 16) + self.open_atos() def open_atos(self): if DEBUG: print 'atos -o %s -arch %s' % (self.binary, self.arch) cmdline = ['atos', '-o', self.binary, '-arch', self.arch] - self.pipe = subprocess.Popen(cmdline, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + self.atos = UnbufferedLineConverter(cmdline, close_stderr=True) def symbolize(self, addr, binary, offset): """Overrides Symbolizer.symbolize.""" if self.binary != binary: return None - self.open_atos() - self.write_addr_to_pipe(offset) - self.pipe.stdin.close() - atos_line = self.pipe.stdout.readline().rstrip() + atos_line = self.atos.convert('0x%x' % int(offset, 16)) + while "got symbolicator for" in atos_line: + atos_line = self.atos.readline() # A well-formed atos response looks like this: # foo(type1, type2) (in object.name) (filename.cc:80) match = re.match('^(.*) \(in (.*)\) \((.*:\d*)\)$', atos_line) @@ -331,7 +355,10 @@ class SymbolizationLoop(object): def process_stdin(self): self.frame_no = 0 - for line in sys.stdin: + while True: + line = sys.stdin.readline() + if not line: + break self.current_line = line.rstrip() #0 0x7f6e35cf2e45 (/blah/foo.so+0x11fe45) stack_trace_line_format = ( diff --git a/lib/asan/tests/CMakeLists.txt b/lib/asan/tests/CMakeLists.txt index 80d6f5d67aad..fc0f1788bd35 100644 --- a/lib/asan/tests/CMakeLists.txt +++ b/lib/asan/tests/CMakeLists.txt @@ -36,13 +36,9 @@ set(ASAN_UNITTEST_COMMON_CFLAGS -Wall -Wno-format -Werror + -Werror=sign-compare -g - -O2 -) - -if(ASAN_TESTS_USE_ZERO_BASE_SHADOW) - list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -fPIE) -endif() + -O2) if(SUPPORTS_NO_VARIADIC_MACROS_FLAG) list(APPEND ASAN_UNITTEST_COMMON_CFLAGS -Wno-variadic-macros) endif() @@ -62,24 +58,7 @@ else() -DASAN_NEEDS_SEGV=1) endif() -set(ASAN_LINK_FLAGS) -if(ASAN_TESTS_USE_ZERO_BASE_SHADOW) - list(APPEND ASAN_LINK_FLAGS -pie) -endif() -# On Android, we link with ASan runtime manually. On other platforms we depend -# on Clang driver behavior, passing -fsanitize=address flag. -if(NOT ANDROID) - list(APPEND ASAN_LINK_FLAGS -fsanitize=address) -endif() -# Unit tests on Mac depend on Foundation. -if(APPLE) - list(APPEND ASAN_LINK_FLAGS -framework Foundation) -endif() -# Unit tests require libstdc++. -list(APPEND ASAN_LINK_FLAGS -lstdc++) - set(ASAN_BLACKLIST_FILE "${CMAKE_CURRENT_SOURCE_DIR}/asan_test.ignore") - set(ASAN_UNITTEST_INSTRUMENTED_CFLAGS ${ASAN_UNITTEST_COMMON_CFLAGS} -fsanitize=address @@ -88,35 +67,65 @@ set(ASAN_UNITTEST_INSTRUMENTED_CFLAGS -mllvm -asan-globals=1 -mllvm -asan-mapping-scale=0 # default will be used -mllvm -asan-mapping-offset-log=-1 # default will be used - -mllvm -asan-use-after-return=0 ) if(ASAN_TESTS_USE_ZERO_BASE_SHADOW) list(APPEND ASAN_UNITTEST_INSTRUMENTED_CFLAGS -fsanitize-address-zero-base-shadow) endif() +# Unit tests require libstdc++. +set(ASAN_UNITTEST_COMMON_LINKFLAGS -lstdc++) +# Unit tests on Mac depend on Foundation. +if(APPLE) + list(APPEND ASAN_UNITTEST_COMMON_LINKFLAGS -framework Foundation) +endif() +if(ASAN_TESTS_USE_ZERO_BASE_SHADOW) + list(APPEND ASAN_UNITTEST_COMMON_LINKFLAGS -pie) +endif() + +set(ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS + ${ASAN_UNITTEST_COMMON_LINKFLAGS}) +# On Android, we link with ASan runtime manually. On other platforms we depend +# on Clang driver behavior, passing -fsanitize=address flag. +if(NOT ANDROID) + list(APPEND ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS -fsanitize=address) +endif() + +set(ASAN_UNITTEST_NOINST_LINKFLAGS + ${ASAN_UNITTEST_COMMON_LINKFLAGS} + -ldl -lm) +if(NOT ANDROID) + list(APPEND ASAN_UNITTEST_NOINST_LINKFLAGS -lpthread) +endif() + # Compile source for the given architecture, using compiler # options in ${ARGN}, and add it to the object list. macro(asan_compile obj_list source arch) get_filename_component(basename ${source} NAME) - set(output_obj "${basename}.${arch}.o") + set(output_obj "${obj_list}.${basename}.${arch}.o") get_target_flags_for_arch(${arch} TARGET_CFLAGS) clang_compile(${output_obj} ${source} CFLAGS ${ARGN} ${TARGET_CFLAGS} - DEPS gtest ${ASAN_RUNTIME_LIBRARIES} + DEPS gtest asan_runtime_libraries ${ASAN_UNITTEST_HEADERS} ${ASAN_BLACKLIST_FILE}) list(APPEND ${obj_list} ${output_obj}) endmacro() # Link ASan unit test for a given architecture from a set -# of objects in ${ARGN}. +# of objects in with given linker flags. macro(add_asan_test test_suite test_name arch) + parse_arguments(TEST "OBJECTS;LINKFLAGS" "WITH_TEST_RUNTIME" ${ARGN}) get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS) + set(TEST_DEPS asan_runtime_libraries ${TEST_OBJECTS}) + if(TEST_WITH_TEST_RUNTIME) + list(APPEND TEST_DEPS ${ASAN_TEST_RUNTIME}) + list(APPEND TEST_OBJECTS lib${ASAN_TEST_RUNTIME}.a) + endif() add_compiler_rt_test(${test_suite} ${test_name} - OBJECTS ${ARGN} - DEPS ${ASAN_RUNTIME_LIBRARIES} ${ARGN} - LINK_FLAGS ${ASAN_LINK_FLAGS} + OBJECTS ${TEST_OBJECTS} + DEPS ${TEST_DEPS} + LINK_FLAGS ${TEST_LINKFLAGS} ${TARGET_LINK_FLAGS}) endmacro() @@ -128,52 +137,84 @@ add_custom_target(AsanBenchmarks) set_target_properties(AsanBenchmarks PROPERTIES FOLDER "Asan benchmarks") set(ASAN_NOINST_TEST_SOURCES + ${COMPILER_RT_GTEST_SOURCE} + asan_fake_stack_test.cc asan_noinst_test.cc asan_test_main.cc) + set(ASAN_INST_TEST_SOURCES + ${COMPILER_RT_GTEST_SOURCE} asan_globals_test.cc + asan_interface_test.cc asan_test.cc asan_oob_test.cc asan_mem_test.cc - asan_str_test.cc) + asan_str_test.cc + asan_test_main.cc) +if(APPLE) + list(APPEND ASAN_INST_TEST_SOURCES asan_mac_test.cc) +endif() + +set(ASAN_BENCHMARKS_SOURCES + ${COMPILER_RT_GTEST_SOURCE} + asan_benchmarks_test.cc) # Adds ASan unit tests and benchmarks for architecture. macro(add_asan_tests_for_arch arch) - # Build gtest instrumented with ASan. - set(ASAN_INST_GTEST) - asan_compile(ASAN_INST_GTEST ${COMPILER_RT_GTEST_SOURCE} ${arch} - ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS}) # Instrumented tests. set(ASAN_INST_TEST_OBJECTS) foreach(src ${ASAN_INST_TEST_SOURCES}) asan_compile(ASAN_INST_TEST_OBJECTS ${src} ${arch} ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS}) endforeach() - # Add Mac-specific tests. if (APPLE) - asan_compile(ASAN_INST_TEST_OBJECTS asan_mac_test.cc ${arch} - ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS}) + # Add Mac-specific helper. asan_compile(ASAN_INST_TEST_OBJECTS asan_mac_test_helpers.mm ${arch} ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS} -ObjC) endif() + add_asan_test(AsanUnitTests "Asan-${arch}-Test" ${arch} + OBJECTS ${ASAN_INST_TEST_OBJECTS} + LINKFLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS}) + + # Add static ASan runtime that will be linked with uninstrumented tests. + set(ASAN_TEST_RUNTIME RTAsanTest.${arch}) + if(APPLE) + set(ASAN_TEST_RUNTIME_OBJECTS + $ + $ + $ + $) + else() + set(ASAN_TEST_RUNTIME_OBJECTS + $ + $ + $ + $ + $) + endif() + add_library(${ASAN_TEST_RUNTIME} STATIC ${ASAN_TEST_RUNTIME_OBJECTS}) + set_target_properties(${ASAN_TEST_RUNTIME} PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) # Uninstrumented tests. set(ASAN_NOINST_TEST_OBJECTS) foreach(src ${ASAN_NOINST_TEST_SOURCES}) asan_compile(ASAN_NOINST_TEST_OBJECTS ${src} ${arch} ${ASAN_UNITTEST_COMMON_CFLAGS}) endforeach() - # Link everything together. - add_asan_test(AsanUnitTests "Asan-${arch}-Test" ${arch} - ${ASAN_NOINST_TEST_OBJECTS} - ${ASAN_INST_TEST_OBJECTS} ${ASAN_INST_GTEST}) + add_asan_test(AsanUnitTests "Asan-${arch}-Noinst-Test" ${arch} + OBJECTS ${ASAN_NOINST_TEST_OBJECTS} + LINKFLAGS ${ASAN_UNITTEST_NOINST_LINKFLAGS} + WITH_TEST_RUNTIME) - # Instrumented benchmarks. + # Benchmarks. set(ASAN_BENCHMARKS_OBJECTS) - asan_compile(ASAN_BENCHMARKS_OBJECTS asan_benchmarks_test.cc ${arch} - ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS}) - # Link benchmarks. + foreach(src ${ASAN_BENCHMARKS_SOURCES}) + asan_compile(ASAN_BENCHMARKS_OBJECTS ${src} ${arch} + ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS}) + endforeach() add_asan_test(AsanBenchmarks "Asan-${arch}-Benchmark" ${arch} - ${ASAN_BENCHMARKS_OBJECTS} ${ASAN_INST_GTEST}) + OBJECTS ${ASAN_BENCHMARKS_OBJECTS} + LINKFLAGS ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS}) endmacro() if(COMPILER_RT_CAN_EXECUTE_TESTS) @@ -185,20 +226,28 @@ endif() if(ANDROID) # We assume that unit tests on Android are built in a build # tree with fresh Clang as a host compiler. - add_library(asan_noinst_test OBJECT ${ASAN_NOINST_TEST_SOURCES}) - set_target_compile_flags(asan_noinst_test ${ASAN_UNITTEST_COMMON_CFLAGS}) - add_library(asan_inst_test OBJECT - ${ASAN_INST_TEST_SOURCES} ${COMPILER_RT_GTEST_SOURCE}) - set_target_compile_flags(asan_inst_test ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS}) + + # Test w/o ASan instrumentation. Link it with ASan statically. + add_executable(AsanNoinstTest + $ + $ + $ + ${COMPILER_RT_GTEST_SOURCE} + ${ASAN_NOINST_TEST_SOURCES}) + set_target_compile_flags(AsanNoinstTest ${ASAN_UNITTEST_COMMON_CFLAGS}) + set_target_link_flags(AsanNoinstTest ${ASAN_UNITTEST_NOINST_LINKFLAGS}) + + # Test with ASan instrumentation. Link with ASan dynamic runtime. add_executable(AsanTest - $ - $ - ) + ${COMPILER_RT_GTEST_SOURCE} + ${ASAN_INST_TEST_SOURCES}) + set_target_compile_flags(AsanTest ${ASAN_UNITTEST_INSTRUMENTED_CFLAGS}) + set_target_link_flags(AsanTest ${ASAN_UNITTEST_INSTRUMENTED_LINKFLAGS}) + target_link_libraries(AsanTest clang_rt.asan-arm-android) + # Setup correct output directory and link flags. - set_target_properties(AsanTest PROPERTIES + set_target_properties(AsanNoinstTest AsanTest PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - set_target_link_flags(AsanTest ${ASAN_LINK_FLAGS}) - target_link_libraries(AsanTest clang_rt.asan-arm-android) # Add unit test to test suite. - add_dependencies(AsanUnitTests AsanTest) + add_dependencies(AsanUnitTests AsanNoinstTest AsanTest) endif() diff --git a/lib/asan/tests/asan_fake_stack_test.cc b/lib/asan/tests/asan_fake_stack_test.cc new file mode 100644 index 000000000000..1c98125eb45e --- /dev/null +++ b/lib/asan/tests/asan_fake_stack_test.cc @@ -0,0 +1,150 @@ +//===-- asan_fake_stack_test.cc -------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +// Tests for FakeStack. +// This test file should be compiled w/o asan instrumentation. +//===----------------------------------------------------------------------===// + +#include "asan_fake_stack.h" +#include "asan_test_utils.h" +#include "sanitizer_common/sanitizer_common.h" + +#include +#include +#include + +#include + +namespace __asan { + +TEST(FakeStack, FlagsSize) { + EXPECT_EQ(FakeStack::SizeRequiredForFlags(10), 1U << 5); + EXPECT_EQ(FakeStack::SizeRequiredForFlags(11), 1U << 6); + EXPECT_EQ(FakeStack::SizeRequiredForFlags(20), 1U << 15); +} + +TEST(FakeStack, RequiredSize) { + // for (int i = 15; i < 20; i++) { + // uptr alloc_size = FakeStack::RequiredSize(i); + // printf("%zdK ==> %zd\n", 1 << (i - 10), alloc_size); + // } + EXPECT_EQ(FakeStack::RequiredSize(15), 365568U); + EXPECT_EQ(FakeStack::RequiredSize(16), 727040U); + EXPECT_EQ(FakeStack::RequiredSize(17), 1449984U); + EXPECT_EQ(FakeStack::RequiredSize(18), 2895872U); + EXPECT_EQ(FakeStack::RequiredSize(19), 5787648U); +} + +TEST(FakeStack, FlagsOffset) { + for (uptr stack_size_log = 15; stack_size_log <= 20; stack_size_log++) { + uptr stack_size = 1UL << stack_size_log; + uptr offset = 0; + for (uptr class_id = 0; class_id < FakeStack::kNumberOfSizeClasses; + class_id++) { + uptr frame_size = FakeStack::BytesInSizeClass(class_id); + uptr num_flags = stack_size / frame_size; + EXPECT_EQ(offset, FakeStack::FlagsOffset(stack_size_log, class_id)); + // printf("%zd: %zd => %zd %zd\n", stack_size_log, class_id, offset, + // FakeStack::FlagsOffset(stack_size_log, class_id)); + offset += num_flags; + } + } +} + +TEST(FakeStack, CreateDestroy) { + for (int i = 0; i < 1000; i++) { + for (uptr stack_size_log = 20; stack_size_log <= 22; stack_size_log++) { + FakeStack *fake_stack = FakeStack::Create(stack_size_log); + fake_stack->Destroy(); + } + } +} + +TEST(FakeStack, ModuloNumberOfFrames) { + EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, 0), 0U); + EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<15)), 0U); + EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<10)), 0U); + EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<9)), 0U); + EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<8)), 1U<<8); + EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 0, (1<<15) + 1), 1U); + + EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 0), 0U); + EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 1<<9), 0U); + EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 1<<8), 0U); + EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 1, 1<<7), 1U<<7); + + EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 0), 0U); + EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 1), 1U); + EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 15), 15U); + EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 16), 0U); + EXPECT_EQ(FakeStack::ModuloNumberOfFrames(15, 5, 17), 1U); +} + +TEST(FakeStack, GetFrame) { + const uptr stack_size_log = 20; + const uptr stack_size = 1 << stack_size_log; + FakeStack *fs = FakeStack::Create(stack_size_log); + u8 *base = fs->GetFrame(stack_size_log, 0, 0); + EXPECT_EQ(base, reinterpret_cast(fs) + + fs->SizeRequiredForFlags(stack_size_log) + 4096); + EXPECT_EQ(base + 0*stack_size + 64 * 7, fs->GetFrame(stack_size_log, 0, 7U)); + EXPECT_EQ(base + 1*stack_size + 128 * 3, fs->GetFrame(stack_size_log, 1, 3U)); + EXPECT_EQ(base + 2*stack_size + 256 * 5, fs->GetFrame(stack_size_log, 2, 5U)); + fs->Destroy(); +} + +TEST(FakeStack, Allocate) { + const uptr stack_size_log = 19; + FakeStack *fs = FakeStack::Create(stack_size_log); + std::map s; + for (int iter = 0; iter < 2; iter++) { + s.clear(); + for (uptr cid = 0; cid < FakeStack::kNumberOfSizeClasses; cid++) { + uptr n = FakeStack::NumberOfFrames(stack_size_log, cid); + uptr bytes_in_class = FakeStack::BytesInSizeClass(cid); + for (uptr j = 0; j < n; j++) { + FakeFrame *ff = fs->Allocate(stack_size_log, cid, 0); + uptr x = reinterpret_cast(ff); + EXPECT_TRUE(s.insert(std::make_pair(ff, cid)).second); + EXPECT_EQ(x, fs->AddrIsInFakeStack(x)); + EXPECT_EQ(x, fs->AddrIsInFakeStack(x + 1)); + EXPECT_EQ(x, fs->AddrIsInFakeStack(x + bytes_in_class - 1)); + EXPECT_NE(x, fs->AddrIsInFakeStack(x + bytes_in_class)); + } + // We are out of fake stack, so Allocate should return 0. + EXPECT_EQ(0UL, fs->Allocate(stack_size_log, cid, 0)); + } + for (std::map::iterator it = s.begin(); it != s.end(); + ++it) { + fs->Deallocate(reinterpret_cast(it->first), it->second); + } + } + fs->Destroy(); +} + +static void RecursiveFunction(FakeStack *fs, int depth) { + uptr class_id = depth / 3; + FakeFrame *ff = fs->Allocate(fs->stack_size_log(), class_id, 0); + if (depth) { + RecursiveFunction(fs, depth - 1); + RecursiveFunction(fs, depth - 1); + } + fs->Deallocate(reinterpret_cast(ff), class_id); +} + +TEST(FakeStack, RecursiveStressTest) { + const uptr stack_size_log = 16; + FakeStack *fs = FakeStack::Create(stack_size_log); + RecursiveFunction(fs, 22); // with 26 runs for 2-3 seconds. + fs->Destroy(); +} + +} // namespace __asan diff --git a/lib/asan/tests/asan_interface_test.cc b/lib/asan/tests/asan_interface_test.cc new file mode 100644 index 000000000000..f36679012f27 --- /dev/null +++ b/lib/asan/tests/asan_interface_test.cc @@ -0,0 +1,426 @@ +//===-- asan_interface_test.cc --------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of AddressSanitizer, an address sanity checker. +// +//===----------------------------------------------------------------------===// +#include "asan_test_utils.h" +#include "sanitizer/asan_interface.h" + +TEST(AddressSanitizerInterface, GetEstimatedAllocatedSize) { + EXPECT_EQ(0U, __asan_get_estimated_allocated_size(0)); + const size_t sizes[] = { 1, 30, 1<<30 }; + for (size_t i = 0; i < 3; i++) { + EXPECT_EQ(sizes[i], __asan_get_estimated_allocated_size(sizes[i])); + } +} + +static const char* kGetAllocatedSizeErrorMsg = + "attempting to call __asan_get_allocated_size()"; + +TEST(AddressSanitizerInterface, GetAllocatedSizeAndOwnershipTest) { + const size_t kArraySize = 100; + char *array = Ident((char*)malloc(kArraySize)); + int *int_ptr = Ident(new int); + + // Allocated memory is owned by allocator. Allocated size should be + // equal to requested size. + EXPECT_EQ(true, __asan_get_ownership(array)); + EXPECT_EQ(kArraySize, __asan_get_allocated_size(array)); + EXPECT_EQ(true, __asan_get_ownership(int_ptr)); + EXPECT_EQ(sizeof(int), __asan_get_allocated_size(int_ptr)); + + // We cannot call GetAllocatedSize from the memory we didn't map, + // and from the interior pointers (not returned by previous malloc). + void *wild_addr = (void*)0x1; + EXPECT_FALSE(__asan_get_ownership(wild_addr)); + EXPECT_DEATH(__asan_get_allocated_size(wild_addr), kGetAllocatedSizeErrorMsg); + EXPECT_FALSE(__asan_get_ownership(array + kArraySize / 2)); + EXPECT_DEATH(__asan_get_allocated_size(array + kArraySize / 2), + kGetAllocatedSizeErrorMsg); + + // NULL is not owned, but is a valid argument for __asan_get_allocated_size(). + EXPECT_FALSE(__asan_get_ownership(NULL)); + EXPECT_EQ(0U, __asan_get_allocated_size(NULL)); + + // When memory is freed, it's not owned, and call to GetAllocatedSize + // is forbidden. + free(array); + EXPECT_FALSE(__asan_get_ownership(array)); + EXPECT_DEATH(__asan_get_allocated_size(array), kGetAllocatedSizeErrorMsg); + delete int_ptr; + + void *zero_alloc = Ident(malloc(0)); + if (zero_alloc != 0) { + // If malloc(0) is not null, this pointer is owned and should have valid + // allocated size. + EXPECT_TRUE(__asan_get_ownership(zero_alloc)); + // Allocated size is 0 or 1 depending on the allocator used. + EXPECT_LT(__asan_get_allocated_size(zero_alloc), 2U); + } + free(zero_alloc); +} + +TEST(AddressSanitizerInterface, GetCurrentAllocatedBytesTest) { + size_t before_malloc, after_malloc, after_free; + char *array; + const size_t kMallocSize = 100; + before_malloc = __asan_get_current_allocated_bytes(); + + array = Ident((char*)malloc(kMallocSize)); + after_malloc = __asan_get_current_allocated_bytes(); + EXPECT_EQ(before_malloc + kMallocSize, after_malloc); + + free(array); + after_free = __asan_get_current_allocated_bytes(); + EXPECT_EQ(before_malloc, after_free); +} + +TEST(AddressSanitizerInterface, GetHeapSizeTest) { + // asan_allocator2 does not keep huge chunks in free list, but unmaps them. + // The chunk should be greater than the quarantine size, + // otherwise it will be stuck in quarantine instead of being unmaped. + static const size_t kLargeMallocSize = (1 << 28) + 1; // 256M + free(Ident(malloc(kLargeMallocSize))); // Drain quarantine. + size_t old_heap_size = __asan_get_heap_size(); + for (int i = 0; i < 3; i++) { + // fprintf(stderr, "allocating %zu bytes:\n", kLargeMallocSize); + free(Ident(malloc(kLargeMallocSize))); + EXPECT_EQ(old_heap_size, __asan_get_heap_size()); + } +} + +static const size_t kManyThreadsMallocSizes[] = {5, 1UL<<10, 1UL<<14, 357}; +static const size_t kManyThreadsIterations = 250; +static const size_t kManyThreadsNumThreads = + (SANITIZER_WORDSIZE == 32) ? 40 : 200; + +static void *ManyThreadsWithStatsWorker(void *arg) { + (void)arg; + for (size_t iter = 0; iter < kManyThreadsIterations; iter++) { + for (size_t size_index = 0; size_index < 4; size_index++) { + free(Ident(malloc(kManyThreadsMallocSizes[size_index]))); + } + } + // Just one large allocation. + free(Ident(malloc(1 << 20))); + return 0; +} + +TEST(AddressSanitizerInterface, ManyThreadsWithStatsStressTest) { + size_t before_test, after_test, i; + pthread_t threads[kManyThreadsNumThreads]; + before_test = __asan_get_current_allocated_bytes(); + for (i = 0; i < kManyThreadsNumThreads; i++) { + PTHREAD_CREATE(&threads[i], 0, + (void* (*)(void *x))ManyThreadsWithStatsWorker, (void*)i); + } + for (i = 0; i < kManyThreadsNumThreads; i++) { + PTHREAD_JOIN(threads[i], 0); + } + after_test = __asan_get_current_allocated_bytes(); + // ASan stats also reflect memory usage of internal ASan RTL structs, + // so we can't check for equality here. + EXPECT_LT(after_test, before_test + (1UL<<20)); +} + +static void DoDoubleFree() { + int *x = Ident(new int); + delete Ident(x); + delete Ident(x); +} + +TEST(AddressSanitizerInterface, ExitCode) { + int original_exit_code = __asan_set_error_exit_code(7); + EXPECT_EXIT(DoDoubleFree(), ::testing::ExitedWithCode(7), ""); + EXPECT_EQ(7, __asan_set_error_exit_code(8)); + EXPECT_EXIT(DoDoubleFree(), ::testing::ExitedWithCode(8), ""); + EXPECT_EQ(8, __asan_set_error_exit_code(original_exit_code)); + EXPECT_EXIT(DoDoubleFree(), + ::testing::ExitedWithCode(original_exit_code), ""); +} + +static void MyDeathCallback() { + fprintf(stderr, "MyDeathCallback\n"); +} + +TEST(AddressSanitizerInterface, DeathCallbackTest) { + __asan_set_death_callback(MyDeathCallback); + EXPECT_DEATH(DoDoubleFree(), "MyDeathCallback"); + __asan_set_death_callback(NULL); +} + +static const char* kUseAfterPoisonErrorMessage = "use-after-poison"; + +#define GOOD_ACCESS(ptr, offset) \ + EXPECT_FALSE(__asan_address_is_poisoned(ptr + offset)) + +#define BAD_ACCESS(ptr, offset) \ + EXPECT_TRUE(__asan_address_is_poisoned(ptr + offset)) + +TEST(AddressSanitizerInterface, SimplePoisonMemoryRegionTest) { + char *array = Ident((char*)malloc(120)); + // poison array[40..80) + __asan_poison_memory_region(array + 40, 40); + GOOD_ACCESS(array, 39); + GOOD_ACCESS(array, 80); + BAD_ACCESS(array, 40); + BAD_ACCESS(array, 60); + BAD_ACCESS(array, 79); + char value; + EXPECT_DEATH(value = Ident(array[40]), kUseAfterPoisonErrorMessage); + __asan_unpoison_memory_region(array + 40, 40); + // access previously poisoned memory. + GOOD_ACCESS(array, 40); + GOOD_ACCESS(array, 79); + free(array); +} + +TEST(AddressSanitizerInterface, OverlappingPoisonMemoryRegionTest) { + char *array = Ident((char*)malloc(120)); + // Poison [0..40) and [80..120) + __asan_poison_memory_region(array, 40); + __asan_poison_memory_region(array + 80, 40); + BAD_ACCESS(array, 20); + GOOD_ACCESS(array, 60); + BAD_ACCESS(array, 100); + // Poison whole array - [0..120) + __asan_poison_memory_region(array, 120); + BAD_ACCESS(array, 60); + // Unpoison [24..96) + __asan_unpoison_memory_region(array + 24, 72); + BAD_ACCESS(array, 23); + GOOD_ACCESS(array, 24); + GOOD_ACCESS(array, 60); + GOOD_ACCESS(array, 95); + BAD_ACCESS(array, 96); + free(array); +} + +TEST(AddressSanitizerInterface, PushAndPopWithPoisoningTest) { + // Vector of capacity 20 + char *vec = Ident((char*)malloc(20)); + __asan_poison_memory_region(vec, 20); + for (size_t i = 0; i < 7; i++) { + // Simulate push_back. + __asan_unpoison_memory_region(vec + i, 1); + GOOD_ACCESS(vec, i); + BAD_ACCESS(vec, i + 1); + } + for (size_t i = 7; i > 0; i--) { + // Simulate pop_back. + __asan_poison_memory_region(vec + i - 1, 1); + BAD_ACCESS(vec, i - 1); + if (i > 1) GOOD_ACCESS(vec, i - 2); + } + free(vec); +} + +// Make sure that each aligned block of size "2^granularity" doesn't have +// "true" value before "false" value. +static void MakeShadowValid(bool *shadow, int length, int granularity) { + bool can_be_poisoned = true; + for (int i = length - 1; i >= 0; i--) { + if (!shadow[i]) + can_be_poisoned = false; + if (!can_be_poisoned) + shadow[i] = false; + if (i % (1 << granularity) == 0) { + can_be_poisoned = true; + } + } +} + +TEST(AddressSanitizerInterface, PoisoningStressTest) { + const size_t kSize = 24; + bool expected[kSize]; + char *arr = Ident((char*)malloc(kSize)); + for (size_t l1 = 0; l1 < kSize; l1++) { + for (size_t s1 = 1; l1 + s1 <= kSize; s1++) { + for (size_t l2 = 0; l2 < kSize; l2++) { + for (size_t s2 = 1; l2 + s2 <= kSize; s2++) { + // Poison [l1, l1+s1), [l2, l2+s2) and check result. + __asan_unpoison_memory_region(arr, kSize); + __asan_poison_memory_region(arr + l1, s1); + __asan_poison_memory_region(arr + l2, s2); + memset(expected, false, kSize); + memset(expected + l1, true, s1); + MakeShadowValid(expected, kSize, /*granularity*/ 3); + memset(expected + l2, true, s2); + MakeShadowValid(expected, kSize, /*granularity*/ 3); + for (size_t i = 0; i < kSize; i++) { + ASSERT_EQ(expected[i], __asan_address_is_poisoned(arr + i)); + } + // Unpoison [l1, l1+s1) and [l2, l2+s2) and check result. + __asan_poison_memory_region(arr, kSize); + __asan_unpoison_memory_region(arr + l1, s1); + __asan_unpoison_memory_region(arr + l2, s2); + memset(expected, true, kSize); + memset(expected + l1, false, s1); + MakeShadowValid(expected, kSize, /*granularity*/ 3); + memset(expected + l2, false, s2); + MakeShadowValid(expected, kSize, /*granularity*/ 3); + for (size_t i = 0; i < kSize; i++) { + ASSERT_EQ(expected[i], __asan_address_is_poisoned(arr + i)); + } + } + } + } + } + free(arr); +} + +TEST(AddressSanitizerInterface, GlobalRedzones) { + GOOD_ACCESS(glob1, 1 - 1); + GOOD_ACCESS(glob2, 2 - 1); + GOOD_ACCESS(glob3, 3 - 1); + GOOD_ACCESS(glob4, 4 - 1); + GOOD_ACCESS(glob5, 5 - 1); + GOOD_ACCESS(glob6, 6 - 1); + GOOD_ACCESS(glob7, 7 - 1); + GOOD_ACCESS(glob8, 8 - 1); + GOOD_ACCESS(glob9, 9 - 1); + GOOD_ACCESS(glob10, 10 - 1); + GOOD_ACCESS(glob11, 11 - 1); + GOOD_ACCESS(glob12, 12 - 1); + GOOD_ACCESS(glob13, 13 - 1); + GOOD_ACCESS(glob14, 14 - 1); + GOOD_ACCESS(glob15, 15 - 1); + GOOD_ACCESS(glob16, 16 - 1); + GOOD_ACCESS(glob17, 17 - 1); + GOOD_ACCESS(glob1000, 1000 - 1); + GOOD_ACCESS(glob10000, 10000 - 1); + GOOD_ACCESS(glob100000, 100000 - 1); + + BAD_ACCESS(glob1, 1); + BAD_ACCESS(glob2, 2); + BAD_ACCESS(glob3, 3); + BAD_ACCESS(glob4, 4); + BAD_ACCESS(glob5, 5); + BAD_ACCESS(glob6, 6); + BAD_ACCESS(glob7, 7); + BAD_ACCESS(glob8, 8); + BAD_ACCESS(glob9, 9); + BAD_ACCESS(glob10, 10); + BAD_ACCESS(glob11, 11); + BAD_ACCESS(glob12, 12); + BAD_ACCESS(glob13, 13); + BAD_ACCESS(glob14, 14); + BAD_ACCESS(glob15, 15); + BAD_ACCESS(glob16, 16); + BAD_ACCESS(glob17, 17); + BAD_ACCESS(glob1000, 1000); + BAD_ACCESS(glob1000, 1100); // Redzone is at least 101 bytes. + BAD_ACCESS(glob10000, 10000); + BAD_ACCESS(glob10000, 11000); // Redzone is at least 1001 bytes. + BAD_ACCESS(glob100000, 100000); + BAD_ACCESS(glob100000, 110000); // Redzone is at least 10001 bytes. +} + +TEST(AddressSanitizerInterface, PoisonedRegion) { + size_t rz = 16; + for (size_t size = 1; size <= 64; size++) { + char *p = new char[size]; + for (size_t beg = 0; beg < size + rz; beg++) { + for (size_t end = beg; end < size + rz; end++) { + void *first_poisoned = __asan_region_is_poisoned(p + beg, end - beg); + if (beg == end) { + EXPECT_FALSE(first_poisoned); + } else if (beg < size && end <= size) { + EXPECT_FALSE(first_poisoned); + } else if (beg >= size) { + EXPECT_EQ(p + beg, first_poisoned); + } else { + EXPECT_GT(end, size); + EXPECT_EQ(p + size, first_poisoned); + } + } + } + delete [] p; + } +} + +// This is a performance benchmark for manual runs. +// asan's memset interceptor calls mem_is_zero for the entire shadow region. +// the profile should look like this: +// 89.10% [.] __memset_sse2 +// 10.50% [.] __sanitizer::mem_is_zero +// I.e. mem_is_zero should consume ~ SHADOW_GRANULARITY less CPU cycles +// than memset itself. +TEST(AddressSanitizerInterface, DISABLED_StressLargeMemset) { + size_t size = 1 << 20; + char *x = new char[size]; + for (int i = 0; i < 100000; i++) + Ident(memset)(x, 0, size); + delete [] x; +} + +// Same here, but we run memset with small sizes. +TEST(AddressSanitizerInterface, DISABLED_StressSmallMemset) { + size_t size = 32; + char *x = new char[size]; + for (int i = 0; i < 100000000; i++) + Ident(memset)(x, 0, size); + delete [] x; +} +static const char *kInvalidPoisonMessage = "invalid-poison-memory-range"; +static const char *kInvalidUnpoisonMessage = "invalid-unpoison-memory-range"; + +TEST(AddressSanitizerInterface, DISABLED_InvalidPoisonAndUnpoisonCallsTest) { + char *array = Ident((char*)malloc(120)); + __asan_unpoison_memory_region(array, 120); + // Try to unpoison not owned memory + EXPECT_DEATH(__asan_unpoison_memory_region(array, 121), + kInvalidUnpoisonMessage); + EXPECT_DEATH(__asan_unpoison_memory_region(array - 1, 120), + kInvalidUnpoisonMessage); + + __asan_poison_memory_region(array, 120); + // Try to poison not owned memory. + EXPECT_DEATH(__asan_poison_memory_region(array, 121), kInvalidPoisonMessage); + EXPECT_DEATH(__asan_poison_memory_region(array - 1, 120), + kInvalidPoisonMessage); + free(array); +} + +static void ErrorReportCallbackOneToZ(const char *report) { + int report_len = strlen(report); + ASSERT_EQ(6, write(2, "ABCDEF", 6)); + ASSERT_EQ(report_len, write(2, report, report_len)); + ASSERT_EQ(6, write(2, "ABCDEF", 6)); + _exit(1); +} + +TEST(AddressSanitizerInterface, SetErrorReportCallbackTest) { + __asan_set_error_report_callback(ErrorReportCallbackOneToZ); + EXPECT_DEATH(__asan_report_error(0, 0, 0, 0, true, 1), + ASAN_PCRE_DOTALL "ABCDEF.*AddressSanitizer.*WRITE.*ABCDEF"); + __asan_set_error_report_callback(NULL); +} + +TEST(AddressSanitizerInterface, GetOwnershipStressTest) { + std::vector pointers; + std::vector sizes; + const size_t kNumMallocs = 1 << 9; + for (size_t i = 0; i < kNumMallocs; i++) { + size_t size = i * 100 + 1; + pointers.push_back((char*)malloc(size)); + sizes.push_back(size); + } + for (size_t i = 0; i < 4000000; i++) { + EXPECT_FALSE(__asan_get_ownership(&pointers)); + EXPECT_FALSE(__asan_get_ownership((void*)0x1234)); + size_t idx = i % kNumMallocs; + EXPECT_TRUE(__asan_get_ownership(pointers[idx])); + EXPECT_EQ(sizes[idx], __asan_get_allocated_size(pointers[idx])); + } + for (size_t i = 0, n = pointers.size(); i < n; i++) + free(pointers[i]); +} + diff --git a/lib/asan/tests/asan_mac_test_helpers.mm b/lib/asan/tests/asan_mac_test_helpers.mm index 4cbd2bb247fd..a7e4b9d1928b 100644 --- a/lib/asan/tests/asan_mac_test_helpers.mm +++ b/lib/asan/tests/asan_mac_test_helpers.mm @@ -1,5 +1,6 @@ // Mac OS X 10.6 or higher only. #include +#include // for pthread_yield_np() #include #include #include @@ -11,26 +12,26 @@ // This is a (void*)(void*) function so it can be passed to pthread_create. void *CFAllocatorDefaultDoubleFree(void *unused) { - void *mem = CFAllocatorAllocate(kCFAllocatorDefault, 5, 0); + void *mem = CFAllocatorAllocate(kCFAllocatorDefault, 5, 0); CFAllocatorDeallocate(kCFAllocatorDefault, mem); CFAllocatorDeallocate(kCFAllocatorDefault, mem); return 0; } void CFAllocatorSystemDefaultDoubleFree() { - void *mem = CFAllocatorAllocate(kCFAllocatorSystemDefault, 5, 0); + void *mem = CFAllocatorAllocate(kCFAllocatorSystemDefault, 5, 0); CFAllocatorDeallocate(kCFAllocatorSystemDefault, mem); CFAllocatorDeallocate(kCFAllocatorSystemDefault, mem); } void CFAllocatorMallocDoubleFree() { - void *mem = CFAllocatorAllocate(kCFAllocatorMalloc, 5, 0); + void *mem = CFAllocatorAllocate(kCFAllocatorMalloc, 5, 0); CFAllocatorDeallocate(kCFAllocatorMalloc, mem); CFAllocatorDeallocate(kCFAllocatorMalloc, mem); } void CFAllocatorMallocZoneDoubleFree() { - void *mem = CFAllocatorAllocate(kCFAllocatorMallocZone, 5, 0); + void *mem = CFAllocatorAllocate(kCFAllocatorMallocZone, 5, 0); CFAllocatorDeallocate(kCFAllocatorMallocZone, mem); CFAllocatorDeallocate(kCFAllocatorMallocZone, mem); } @@ -77,10 +78,17 @@ void worker_do_crash(int size) { free(mem); } +// Used by the GCD tests to avoid a race between the worker thread reporting a +// memory error and the main thread which may exit with exit code 0 before +// that. +void wait_forever() { + volatile bool infinite = true; + while (infinite) pthread_yield_np(); +} + // Tests for the Grand Central Dispatch. See // http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html // for the reference. - void TestGCDDispatchAsync() { dispatch_queue_t queue = dispatch_get_global_queue(0, 0); dispatch_block_t block = ^{ worker_do_crash(1024); }; @@ -88,8 +96,7 @@ void TestGCDDispatchAsync() { // pthread_create(). We need to verify that AddressSanitizer notices that the // thread has started. dispatch_async(queue, block); - // TODO(glider): this is hacky. Need to wait for the worker instead. - sleep(1); + wait_forever(); } void TestGCDDispatchSync() { @@ -99,8 +106,7 @@ void TestGCDDispatchSync() { // pthread_create(). We need to verify that AddressSanitizer notices that the // thread has started. dispatch_sync(queue, block); - // TODO(glider): this is hacky. Need to wait for the worker instead. - sleep(1); + wait_forever(); } // libdispatch spawns a rather small number of threads and reuses them. We need @@ -113,8 +119,7 @@ void TestGCDReuseWqthreadsAsync() { dispatch_async(queue, block_alloc); } dispatch_async(queue, block_crash); - // TODO(glider): this is hacky. Need to wait for the workers instead. - sleep(1); + wait_forever(); } // Try to trigger abnormal behaviour of dispatch_sync() being unhandled by us. @@ -130,8 +135,7 @@ void TestGCDReuseWqthreadsSync() { dispatch_sync(queue[i % 4], block_alloc); } dispatch_sync(queue[3], block_crash); - // TODO(glider): this is hacky. Need to wait for the workers instead. - sleep(1); + wait_forever(); } void TestGCDDispatchAfter() { @@ -141,9 +145,7 @@ void TestGCDDispatchAfter() { dispatch_time_t milestone = dispatch_time(DISPATCH_TIME_NOW, 1LL * NSEC_PER_SEC); dispatch_after(milestone, queue, block_crash); - // Let's wait for a bit longer now. - // TODO(glider): this is still hacky. - sleep(2); + wait_forever(); } void worker_do_deallocate(void *ptr) { @@ -172,7 +174,7 @@ void TestGCDSourceEvent() { access_memory(&mem[10]); }); dispatch_resume(timer); - sleep(2); + wait_forever(); } void TestGCDSourceCancel() { @@ -196,7 +198,7 @@ void TestGCDSourceCancel() { access_memory(&mem[10]); }); dispatch_resume(timer); - sleep(2); + wait_forever(); } void TestGCDGroupAsync() { @@ -207,6 +209,7 @@ void TestGCDGroupAsync() { access_memory(&mem[10]); }); dispatch_group_wait(group, DISPATCH_TIME_FOREVER); + wait_forever(); } @interface FixedArray : NSObject { diff --git a/lib/asan/tests/asan_noinst_test.cc b/lib/asan/tests/asan_noinst_test.cc index 54fdd1979b8e..cb6223c09a46 100644 --- a/lib/asan/tests/asan_noinst_test.cc +++ b/lib/asan/tests/asan_noinst_test.cc @@ -25,6 +25,46 @@ #include #include +#if ASAN_FLEXIBLE_MAPPING_AND_OFFSET == 1 +// Manually set correct ASan mapping scale and offset, as they won't be +// exported from instrumented sources (there are none). +# define FLEXIBLE_SHADOW_SCALE kDefaultShadowScale +# if SANITIZER_ANDROID +# define FLEXIBLE_SHADOW_OFFSET (0) +# else +# if SANITIZER_WORDSIZE == 32 +# if defined(__mips__) +# define FLEXIBLE_SHADOW_OFFSET kMIPS32_ShadowOffset32 +# else +# define FLEXIBLE_SHADOW_OFFSET kDefaultShadowOffset32 +# endif +# else +# if defined(__powerpc64__) +# define FLEXIBLE_SHADOW_OFFSET kPPC64_ShadowOffset64 +# elif SANITIZER_MAC +# define FLEXIBLE_SHADOW_OFFSET kDefaultShadowOffset64 +# else +# define FLEXIBLE_SHADOW_OFFSET kDefaultShort64bitShadowOffset +# endif +# endif +# endif +SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_mapping_scale = FLEXIBLE_SHADOW_SCALE; +SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_mapping_offset = + FLEXIBLE_SHADOW_OFFSET; +#endif // ASAN_FLEXIBLE_MAPPING_AND_OFFSET + +extern "C" { +// Set specific ASan options for uninstrumented unittest. +const char* __asan_default_options() { + return "allow_reexec=0"; +} +} // extern "C" + +// Make sure __asan_init is called before any test case is run. +struct AsanInitCaller { + AsanInitCaller() { __asan_init(); } +}; +static AsanInitCaller asan_init_caller; TEST(AddressSanitizer, InternalSimpleDeathTest) { EXPECT_DEATH(exit(1), ""); @@ -66,6 +106,7 @@ static void MallocStress(size_t n) { size_t alignment = 1 << (my_rand_r(&seed) % 10 + 1); char *ptr = (char*)__asan::asan_memalign(alignment, size, &stack2, __asan::FROM_MALLOC); + EXPECT_EQ(size, __asan::asan_malloc_usable_size(ptr, 0, 0)); vec.push_back(ptr); ptr[0] = 0; ptr[size-1] = 0; @@ -118,144 +159,6 @@ TEST(AddressSanitizer, DISABLED_InternalPrintShadow) { } } -static uptr pc_array[] = { -#if SANITIZER_WORDSIZE == 64 - 0x7effbf756068ULL, - 0x7effbf75e5abULL, - 0x7effc0625b7cULL, - 0x7effc05b8997ULL, - 0x7effbf990577ULL, - 0x7effbf990c56ULL, - 0x7effbf992f3cULL, - 0x7effbf950c22ULL, - 0x7effc036dba0ULL, - 0x7effc03638a3ULL, - 0x7effc035be4aULL, - 0x7effc0539c45ULL, - 0x7effc0539a65ULL, - 0x7effc03db9b3ULL, - 0x7effc03db100ULL, - 0x7effc037c7b8ULL, - 0x7effc037bfffULL, - 0x7effc038b777ULL, - 0x7effc038021cULL, - 0x7effc037c7d1ULL, - 0x7effc037bfffULL, - 0x7effc038b777ULL, - 0x7effc038021cULL, - 0x7effc037c7d1ULL, - 0x7effc037bfffULL, - 0x7effc038b777ULL, - 0x7effc038021cULL, - 0x7effc037c7d1ULL, - 0x7effc037bfffULL, - 0x7effc0520d26ULL, - 0x7effc009ddffULL, - 0x7effbf90bb50ULL, - 0x7effbdddfa69ULL, - 0x7effbdde1fe2ULL, - 0x7effbdde2424ULL, - 0x7effbdde27b3ULL, - 0x7effbddee53bULL, - 0x7effbdde1988ULL, - 0x7effbdde0904ULL, - 0x7effc106ce0dULL, - 0x7effbcc3fa04ULL, - 0x7effbcc3f6a4ULL, - 0x7effbcc3e726ULL, - 0x7effbcc40852ULL, - 0x7effb681ec4dULL, -#endif // SANITIZER_WORDSIZE - 0xB0B5E768, - 0x7B682EC1, - 0x367F9918, - 0xAE34E13, - 0xBA0C6C6, - 0x13250F46, - 0xA0D6A8AB, - 0x2B07C1A8, - 0x6C844F4A, - 0x2321B53, - 0x1F3D4F8F, - 0x3FE2924B, - 0xB7A2F568, - 0xBD23950A, - 0x61020930, - 0x33E7970C, - 0x405998A1, - 0x59F3551D, - 0x350E3028, - 0xBC55A28D, - 0x361F3AED, - 0xBEAD0F73, - 0xAEF28479, - 0x757E971F, - 0xAEBA450, - 0x43AD22F5, - 0x8C2C50C4, - 0x7AD8A2E1, - 0x69EE4EE8, - 0xC08DFF, - 0x4BA6538, - 0x3708AB2, - 0xC24B6475, - 0x7C8890D7, - 0x6662495F, - 0x9B641689, - 0xD3596B, - 0xA1049569, - 0x44CBC16, - 0x4D39C39F -}; - -void CompressStackTraceTest(size_t n_iter) { - u32 seed = my_rand(); - const size_t kNumPcs = ARRAY_SIZE(pc_array); - u32 compressed[2 * kNumPcs]; - - for (size_t iter = 0; iter < n_iter; iter++) { - std::random_shuffle(pc_array, pc_array + kNumPcs); - StackTrace stack0, stack1; - stack0.CopyFrom(pc_array, kNumPcs); - stack0.size = std::max((size_t)1, (size_t)(my_rand_r(&seed) % stack0.size)); - size_t compress_size = - std::max((size_t)2, (size_t)my_rand_r(&seed) % (2 * kNumPcs)); - size_t n_frames = - StackTrace::CompressStack(&stack0, compressed, compress_size); - Ident(n_frames); - assert(n_frames <= stack0.size); - StackTrace::UncompressStack(&stack1, compressed, compress_size); - assert(stack1.size == n_frames); - for (size_t i = 0; i < stack1.size; i++) { - assert(stack0.trace[i] == stack1.trace[i]); - } - } -} - -TEST(AddressSanitizer, CompressStackTraceTest) { - CompressStackTraceTest(10000); -} - -void CompressStackTraceBenchmark(size_t n_iter) { - const size_t kNumPcs = ARRAY_SIZE(pc_array); - u32 compressed[2 * kNumPcs]; - std::random_shuffle(pc_array, pc_array + kNumPcs); - - StackTrace stack0; - stack0.CopyFrom(pc_array, kNumPcs); - stack0.size = kNumPcs; - for (size_t iter = 0; iter < n_iter; iter++) { - size_t compress_size = kNumPcs; - size_t n_frames = - StackTrace::CompressStack(&stack0, compressed, compress_size); - Ident(n_frames); - } -} - -TEST(AddressSanitizer, CompressStackTraceBenchmark) { - CompressStackTraceBenchmark(1 << 24); -} - TEST(AddressSanitizer, QuarantineTest) { StackTrace stack; stack.trace[0] = 0x890; @@ -332,463 +235,13 @@ TEST(AddressSanitizer, ThreadedOneSizeMallocStressTest) { } } -TEST(AddressSanitizer, MemsetWildAddressTest) { +TEST(AddressSanitizer, ShadowRegionIsPoisonedTest) { using __asan::kHighMemEnd; - typedef void*(*memset_p)(void*, int, size_t); - // Prevent inlining of memset(). - volatile memset_p libc_memset = (memset_p)memset; - EXPECT_DEATH(libc_memset((void*)(kLowShadowBeg + 200), 0, 100), - (kLowShadowEnd == 0) ? "unknown-crash.*shadow gap" - : "unknown-crash.*low shadow"); - EXPECT_DEATH(libc_memset((void*)(kShadowGapBeg + 200), 0, 100), - "unknown-crash.*shadow gap"); - EXPECT_DEATH(libc_memset((void*)(kHighShadowBeg + 200), 0, 100), - "unknown-crash.*high shadow"); -} - -TEST(AddressSanitizerInterface, GetEstimatedAllocatedSize) { - EXPECT_EQ(0U, __asan_get_estimated_allocated_size(0)); - const size_t sizes[] = { 1, 30, 1<<30 }; - for (size_t i = 0; i < 3; i++) { - EXPECT_EQ(sizes[i], __asan_get_estimated_allocated_size(sizes[i])); - } -} - -static const char* kGetAllocatedSizeErrorMsg = - "attempting to call __asan_get_allocated_size()"; - -TEST(AddressSanitizerInterface, GetAllocatedSizeAndOwnershipTest) { - const size_t kArraySize = 100; - char *array = Ident((char*)malloc(kArraySize)); - int *int_ptr = Ident(new int); - - // Allocated memory is owned by allocator. Allocated size should be - // equal to requested size. - EXPECT_EQ(true, __asan_get_ownership(array)); - EXPECT_EQ(kArraySize, __asan_get_allocated_size(array)); - EXPECT_EQ(true, __asan_get_ownership(int_ptr)); - EXPECT_EQ(sizeof(int), __asan_get_allocated_size(int_ptr)); - - // We cannot call GetAllocatedSize from the memory we didn't map, - // and from the interior pointers (not returned by previous malloc). - void *wild_addr = (void*)0x1; - EXPECT_FALSE(__asan_get_ownership(wild_addr)); - EXPECT_DEATH(__asan_get_allocated_size(wild_addr), kGetAllocatedSizeErrorMsg); - EXPECT_FALSE(__asan_get_ownership(array + kArraySize / 2)); - EXPECT_DEATH(__asan_get_allocated_size(array + kArraySize / 2), - kGetAllocatedSizeErrorMsg); - - // NULL is not owned, but is a valid argument for __asan_get_allocated_size(). - EXPECT_FALSE(__asan_get_ownership(NULL)); - EXPECT_EQ(0U, __asan_get_allocated_size(NULL)); - - // When memory is freed, it's not owned, and call to GetAllocatedSize - // is forbidden. - free(array); - EXPECT_FALSE(__asan_get_ownership(array)); - EXPECT_DEATH(__asan_get_allocated_size(array), kGetAllocatedSizeErrorMsg); - delete int_ptr; - - void *zero_alloc = Ident(malloc(0)); - if (zero_alloc != 0) { - // If malloc(0) is not null, this pointer is owned and should have valid - // allocated size. - EXPECT_TRUE(__asan_get_ownership(zero_alloc)); - // Allocated size is 0 or 1 depending on the allocator used. - EXPECT_LT(__asan_get_allocated_size(zero_alloc), 2U); - } - free(zero_alloc); -} - -TEST(AddressSanitizerInterface, GetCurrentAllocatedBytesTest) { - size_t before_malloc, after_malloc, after_free; - char *array; - const size_t kMallocSize = 100; - before_malloc = __asan_get_current_allocated_bytes(); - - array = Ident((char*)malloc(kMallocSize)); - after_malloc = __asan_get_current_allocated_bytes(); - EXPECT_EQ(before_malloc + kMallocSize, after_malloc); - - free(array); - after_free = __asan_get_current_allocated_bytes(); - EXPECT_EQ(before_malloc, after_free); -} - -static void DoDoubleFree() { - int *x = Ident(new int); - delete Ident(x); - delete Ident(x); -} - -TEST(AddressSanitizerInterface, GetHeapSizeTest) { - // asan_allocator2 does not keep huge chunks in free list, but unmaps them. - // The chunk should be greater than the quarantine size, - // otherwise it will be stuck in quarantine instead of being unmaped. - static const size_t kLargeMallocSize = (1 << 28) + 1; // 256M - free(Ident(malloc(kLargeMallocSize))); // Drain quarantine. - uptr old_heap_size = __asan_get_heap_size(); - for (int i = 0; i < 3; i++) { - // fprintf(stderr, "allocating %zu bytes:\n", kLargeMallocSize); - free(Ident(malloc(kLargeMallocSize))); - EXPECT_EQ(old_heap_size, __asan_get_heap_size()); - } -} - -static const size_t kManyThreadsMallocSizes[] = {5, 1UL<<10, 1UL<<14, 357}; -static const size_t kManyThreadsIterations = 250; -static const size_t kManyThreadsNumThreads = - (SANITIZER_WORDSIZE == 32) ? 40 : 200; - -void *ManyThreadsWithStatsWorker(void *arg) { - (void)arg; - for (size_t iter = 0; iter < kManyThreadsIterations; iter++) { - for (size_t size_index = 0; size_index < 4; size_index++) { - free(Ident(malloc(kManyThreadsMallocSizes[size_index]))); - } - } - // Just one large allocation. - free(Ident(malloc(1 << 20))); - return 0; -} - -TEST(AddressSanitizerInterface, ManyThreadsWithStatsStressTest) { - size_t before_test, after_test, i; - pthread_t threads[kManyThreadsNumThreads]; - before_test = __asan_get_current_allocated_bytes(); - for (i = 0; i < kManyThreadsNumThreads; i++) { - PTHREAD_CREATE(&threads[i], 0, - (void* (*)(void *x))ManyThreadsWithStatsWorker, (void*)i); - } - for (i = 0; i < kManyThreadsNumThreads; i++) { - PTHREAD_JOIN(threads[i], 0); - } - after_test = __asan_get_current_allocated_bytes(); - // ASan stats also reflect memory usage of internal ASan RTL structs, - // so we can't check for equality here. - EXPECT_LT(after_test, before_test + (1UL<<20)); -} - -TEST(AddressSanitizerInterface, ExitCode) { - int original_exit_code = __asan_set_error_exit_code(7); - EXPECT_EXIT(DoDoubleFree(), ::testing::ExitedWithCode(7), ""); - EXPECT_EQ(7, __asan_set_error_exit_code(8)); - EXPECT_EXIT(DoDoubleFree(), ::testing::ExitedWithCode(8), ""); - EXPECT_EQ(8, __asan_set_error_exit_code(original_exit_code)); - EXPECT_EXIT(DoDoubleFree(), - ::testing::ExitedWithCode(original_exit_code), ""); -} - -static void MyDeathCallback() { - fprintf(stderr, "MyDeathCallback\n"); -} - -TEST(AddressSanitizerInterface, DeathCallbackTest) { - __asan_set_death_callback(MyDeathCallback); - EXPECT_DEATH(DoDoubleFree(), "MyDeathCallback"); - __asan_set_death_callback(NULL); -} - -static const char* kUseAfterPoisonErrorMessage = "use-after-poison"; - -#define GOOD_ACCESS(ptr, offset) \ - EXPECT_FALSE(__asan::AddressIsPoisoned((uptr)(ptr + offset))) - -#define BAD_ACCESS(ptr, offset) \ - EXPECT_TRUE(__asan::AddressIsPoisoned((uptr)(ptr + offset))) - -TEST(AddressSanitizerInterface, SimplePoisonMemoryRegionTest) { - char *array = Ident((char*)malloc(120)); - // poison array[40..80) - __asan_poison_memory_region(array + 40, 40); - GOOD_ACCESS(array, 39); - GOOD_ACCESS(array, 80); - BAD_ACCESS(array, 40); - BAD_ACCESS(array, 60); - BAD_ACCESS(array, 79); - EXPECT_DEATH(__asan_report_error(0, 0, 0, (uptr)(array + 40), true, 1), - kUseAfterPoisonErrorMessage); - __asan_unpoison_memory_region(array + 40, 40); - // access previously poisoned memory. - GOOD_ACCESS(array, 40); - GOOD_ACCESS(array, 79); - free(array); -} - -TEST(AddressSanitizerInterface, OverlappingPoisonMemoryRegionTest) { - char *array = Ident((char*)malloc(120)); - // Poison [0..40) and [80..120) - __asan_poison_memory_region(array, 40); - __asan_poison_memory_region(array + 80, 40); - BAD_ACCESS(array, 20); - GOOD_ACCESS(array, 60); - BAD_ACCESS(array, 100); - // Poison whole array - [0..120) - __asan_poison_memory_region(array, 120); - BAD_ACCESS(array, 60); - // Unpoison [24..96) - __asan_unpoison_memory_region(array + 24, 72); - BAD_ACCESS(array, 23); - GOOD_ACCESS(array, 24); - GOOD_ACCESS(array, 60); - GOOD_ACCESS(array, 95); - BAD_ACCESS(array, 96); - free(array); -} - -TEST(AddressSanitizerInterface, PushAndPopWithPoisoningTest) { - // Vector of capacity 20 - char *vec = Ident((char*)malloc(20)); - __asan_poison_memory_region(vec, 20); - for (size_t i = 0; i < 7; i++) { - // Simulate push_back. - __asan_unpoison_memory_region(vec + i, 1); - GOOD_ACCESS(vec, i); - BAD_ACCESS(vec, i + 1); - } - for (size_t i = 7; i > 0; i--) { - // Simulate pop_back. - __asan_poison_memory_region(vec + i - 1, 1); - BAD_ACCESS(vec, i - 1); - if (i > 1) GOOD_ACCESS(vec, i - 2); - } - free(vec); -} - -TEST(AddressSanitizerInterface, GlobalRedzones) { - GOOD_ACCESS(glob1, 1 - 1); - GOOD_ACCESS(glob2, 2 - 1); - GOOD_ACCESS(glob3, 3 - 1); - GOOD_ACCESS(glob4, 4 - 1); - GOOD_ACCESS(glob5, 5 - 1); - GOOD_ACCESS(glob6, 6 - 1); - GOOD_ACCESS(glob7, 7 - 1); - GOOD_ACCESS(glob8, 8 - 1); - GOOD_ACCESS(glob9, 9 - 1); - GOOD_ACCESS(glob10, 10 - 1); - GOOD_ACCESS(glob11, 11 - 1); - GOOD_ACCESS(glob12, 12 - 1); - GOOD_ACCESS(glob13, 13 - 1); - GOOD_ACCESS(glob14, 14 - 1); - GOOD_ACCESS(glob15, 15 - 1); - GOOD_ACCESS(glob16, 16 - 1); - GOOD_ACCESS(glob17, 17 - 1); - GOOD_ACCESS(glob1000, 1000 - 1); - GOOD_ACCESS(glob10000, 10000 - 1); - GOOD_ACCESS(glob100000, 100000 - 1); - - BAD_ACCESS(glob1, 1); - BAD_ACCESS(glob2, 2); - BAD_ACCESS(glob3, 3); - BAD_ACCESS(glob4, 4); - BAD_ACCESS(glob5, 5); - BAD_ACCESS(glob6, 6); - BAD_ACCESS(glob7, 7); - BAD_ACCESS(glob8, 8); - BAD_ACCESS(glob9, 9); - BAD_ACCESS(glob10, 10); - BAD_ACCESS(glob11, 11); - BAD_ACCESS(glob12, 12); - BAD_ACCESS(glob13, 13); - BAD_ACCESS(glob14, 14); - BAD_ACCESS(glob15, 15); - BAD_ACCESS(glob16, 16); - BAD_ACCESS(glob17, 17); - BAD_ACCESS(glob1000, 1000); - BAD_ACCESS(glob1000, 1100); // Redzone is at least 101 bytes. - BAD_ACCESS(glob10000, 10000); - BAD_ACCESS(glob10000, 11000); // Redzone is at least 1001 bytes. - BAD_ACCESS(glob100000, 100000); - BAD_ACCESS(glob100000, 110000); // Redzone is at least 10001 bytes. -} - -// Make sure that each aligned block of size "2^granularity" doesn't have -// "true" value before "false" value. -static void MakeShadowValid(bool *shadow, int length, int granularity) { - bool can_be_poisoned = true; - for (int i = length - 1; i >= 0; i--) { - if (!shadow[i]) - can_be_poisoned = false; - if (!can_be_poisoned) - shadow[i] = false; - if (i % (1 << granularity) == 0) { - can_be_poisoned = true; - } - } -} - -TEST(AddressSanitizerInterface, PoisoningStressTest) { - const size_t kSize = 24; - bool expected[kSize]; - char *arr = Ident((char*)malloc(kSize)); - for (size_t l1 = 0; l1 < kSize; l1++) { - for (size_t s1 = 1; l1 + s1 <= kSize; s1++) { - for (size_t l2 = 0; l2 < kSize; l2++) { - for (size_t s2 = 1; l2 + s2 <= kSize; s2++) { - // Poison [l1, l1+s1), [l2, l2+s2) and check result. - __asan_unpoison_memory_region(arr, kSize); - __asan_poison_memory_region(arr + l1, s1); - __asan_poison_memory_region(arr + l2, s2); - memset(expected, false, kSize); - memset(expected + l1, true, s1); - MakeShadowValid(expected, kSize, /*granularity*/ 3); - memset(expected + l2, true, s2); - MakeShadowValid(expected, kSize, /*granularity*/ 3); - for (size_t i = 0; i < kSize; i++) { - ASSERT_EQ(expected[i], __asan_address_is_poisoned(arr + i)); - } - // Unpoison [l1, l1+s1) and [l2, l2+s2) and check result. - __asan_poison_memory_region(arr, kSize); - __asan_unpoison_memory_region(arr + l1, s1); - __asan_unpoison_memory_region(arr + l2, s2); - memset(expected, true, kSize); - memset(expected + l1, false, s1); - MakeShadowValid(expected, kSize, /*granularity*/ 3); - memset(expected + l2, false, s2); - MakeShadowValid(expected, kSize, /*granularity*/ 3); - for (size_t i = 0; i < kSize; i++) { - ASSERT_EQ(expected[i], __asan_address_is_poisoned(arr + i)); - } - } - } - } - } -} - -TEST(AddressSanitizerInterface, PoisonedRegion) { - size_t rz = 16; - for (size_t size = 1; size <= 64; size++) { - char *p = new char[size]; - uptr x = reinterpret_cast(p); - for (size_t beg = 0; beg < size + rz; beg++) { - for (size_t end = beg; end < size + rz; end++) { - uptr first_poisoned = __asan_region_is_poisoned(x + beg, end - beg); - if (beg == end) { - EXPECT_FALSE(first_poisoned); - } else if (beg < size && end <= size) { - EXPECT_FALSE(first_poisoned); - } else if (beg >= size) { - EXPECT_EQ(x + beg, first_poisoned); - } else { - EXPECT_GT(end, size); - EXPECT_EQ(x + size, first_poisoned); - } - } - } - delete [] p; - } -} - -// This is a performance benchmark for manual runs. -// asan's memset interceptor calls mem_is_zero for the entire shadow region. -// the profile should look like this: -// 89.10% [.] __memset_sse2 -// 10.50% [.] __sanitizer::mem_is_zero -// I.e. mem_is_zero should consume ~ SHADOW_GRANULARITY less CPU cycles -// than memset itself. -TEST(AddressSanitizerInterface, DISABLED_StressLargeMemset) { - size_t size = 1 << 20; - char *x = new char[size]; - for (int i = 0; i < 100000; i++) - Ident(memset)(x, 0, size); - delete [] x; -} - -// Same here, but we run memset with small sizes. -TEST(AddressSanitizerInterface, DISABLED_StressSmallMemset) { - size_t size = 32; - char *x = new char[size]; - for (int i = 0; i < 100000000; i++) - Ident(memset)(x, 0, size); - delete [] x; -} - -static const char *kInvalidPoisonMessage = "invalid-poison-memory-range"; -static const char *kInvalidUnpoisonMessage = "invalid-unpoison-memory-range"; - -TEST(AddressSanitizerInterface, DISABLED_InvalidPoisonAndUnpoisonCallsTest) { - char *array = Ident((char*)malloc(120)); - __asan_unpoison_memory_region(array, 120); - // Try to unpoison not owned memory - EXPECT_DEATH(__asan_unpoison_memory_region(array, 121), - kInvalidUnpoisonMessage); - EXPECT_DEATH(__asan_unpoison_memory_region(array - 1, 120), - kInvalidUnpoisonMessage); - - __asan_poison_memory_region(array, 120); - // Try to poison not owned memory. - EXPECT_DEATH(__asan_poison_memory_region(array, 121), kInvalidPoisonMessage); - EXPECT_DEATH(__asan_poison_memory_region(array - 1, 120), - kInvalidPoisonMessage); - free(array); -} - -static void ErrorReportCallbackOneToZ(const char *report) { - int report_len = strlen(report); - ASSERT_EQ(6, write(2, "ABCDEF", 6)); - ASSERT_EQ(report_len, write(2, report, report_len)); - ASSERT_EQ(6, write(2, "ABCDEF", 6)); - _exit(1); -} - -TEST(AddressSanitizerInterface, SetErrorReportCallbackTest) { - __asan_set_error_report_callback(ErrorReportCallbackOneToZ); - EXPECT_DEATH(__asan_report_error(0, 0, 0, 0, true, 1), - ASAN_PCRE_DOTALL "ABCDEF.*AddressSanitizer.*WRITE.*ABCDEF"); - __asan_set_error_report_callback(NULL); -} - -TEST(AddressSanitizerInterface, GetOwnershipStressTest) { - std::vector pointers; - std::vector sizes; - const size_t kNumMallocs = 1 << 9; - for (size_t i = 0; i < kNumMallocs; i++) { - size_t size = i * 100 + 1; - pointers.push_back((char*)malloc(size)); - sizes.push_back(size); - } - for (size_t i = 0; i < 4000000; i++) { - EXPECT_FALSE(__asan_get_ownership(&pointers)); - EXPECT_FALSE(__asan_get_ownership((void*)0x1234)); - size_t idx = i % kNumMallocs; - EXPECT_TRUE(__asan_get_ownership(pointers[idx])); - EXPECT_EQ(sizes[idx], __asan_get_allocated_size(pointers[idx])); - } - for (size_t i = 0, n = pointers.size(); i < n; i++) - free(pointers[i]); -} - -TEST(AddressSanitizerInterface, CallocOverflow) { - size_t kArraySize = 4096; - volatile size_t kMaxSizeT = std::numeric_limits::max(); - volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10; - void *p = calloc(kArraySize, kArraySize2); // Should return 0. - EXPECT_EQ(0L, Ident(p)); -} - -TEST(AddressSanitizerInterface, CallocOverflow2) { -#if SANITIZER_WORDSIZE == 32 - size_t kArraySize = 112; - volatile size_t kArraySize2 = 43878406; - void *p = calloc(kArraySize, kArraySize2); // Should return 0. - EXPECT_EQ(0L, Ident(p)); -#endif -} - -TEST(AddressSanitizerInterface, CallocReturnsZeroMem) { - size_t sizes[] = {16, 1000, 10000, 100000, 2100000}; - for (size_t s = 0; s < ARRAY_SIZE(sizes); s++) { - size_t size = sizes[s]; - for (size_t iter = 0; iter < 5; iter++) { - char *x = Ident((char*)calloc(1, size)); - EXPECT_EQ(x[0], 0); - EXPECT_EQ(x[size - 1], 0); - EXPECT_EQ(x[size / 2], 0); - EXPECT_EQ(x[size / 3], 0); - EXPECT_EQ(x[size / 4], 0); - memset(x, 0x42, size); - free(Ident(x)); - free(Ident(malloc(Ident(1 << 27)))); // Try to drain the quarantine. - } - } + // Check that __asan_region_is_poisoned works for shadow regions. + uptr ptr = kLowShadowBeg + 200; + EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100)); + ptr = kShadowGapBeg + 200; + EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100)); + ptr = kHighShadowBeg + 200; + EXPECT_EQ(ptr, __asan_region_is_poisoned(ptr, 100)); } diff --git a/lib/asan/tests/asan_str_test.cc b/lib/asan/tests/asan_str_test.cc index 128fb61c25a9..178d00d4da86 100644 --- a/lib/asan/tests/asan_str_test.cc +++ b/lib/asan/tests/asan_str_test.cc @@ -12,6 +12,10 @@ //===----------------------------------------------------------------------===// #include "asan_test_utils.h" +#if defined(__APPLE__) +#include // For MAC_OS_X_VERSION_* +#endif + // Used for string functions tests static char global_string[] = "global"; static size_t global_string_length = 6; @@ -61,6 +65,18 @@ TEST(AddressSanitizer, StrLenOOBTest) { free(heap_string); } +TEST(AddressSanitizer, WcsLenTest) { + EXPECT_EQ(0U, wcslen(Ident(L""))); + size_t hello_len = 13; + size_t hello_size = (hello_len + 1) * sizeof(wchar_t); + EXPECT_EQ(hello_len, wcslen(Ident(L"Hello, World!"))); + wchar_t *heap_string = Ident((wchar_t*)malloc(hello_size)); + memcpy(heap_string, L"Hello, World!", hello_size); + EXPECT_EQ(hello_len, Ident(wcslen(heap_string))); + EXPECT_DEATH(Ident(wcslen(heap_string + 14)), RightOOBReadMessage(0)); + free(heap_string); +} + #ifndef __APPLE__ TEST(AddressSanitizer, StrNLenOOBTest) { size_t size = Ident(123); diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc index 5ae525de9876..6539ae8af4ea 100644 --- a/lib/asan/tests/asan_test.cc +++ b/lib/asan/tests/asan_test.cc @@ -111,6 +111,24 @@ TEST(AddressSanitizer, CallocTest) { free(a); } +TEST(AddressSanitizer, CallocReturnsZeroMem) { + size_t sizes[] = {16, 1000, 10000, 100000, 2100000}; + for (size_t s = 0; s < sizeof(sizes)/sizeof(sizes[0]); s++) { + size_t size = sizes[s]; + for (size_t iter = 0; iter < 5; iter++) { + char *x = Ident((char*)calloc(1, size)); + EXPECT_EQ(x[0], 0); + EXPECT_EQ(x[size - 1], 0); + EXPECT_EQ(x[size / 2], 0); + EXPECT_EQ(x[size / 3], 0); + EXPECT_EQ(x[size / 4], 0); + memset(x, 0x42, size); + free(Ident(x)); + free(Ident(malloc(Ident(1 << 27)))); // Try to drain the quarantine. + } + } +} + TEST(AddressSanitizer, VallocTest) { void *a = valloc(100); EXPECT_EQ(0U, (uintptr_t)a % kPageSize); @@ -227,16 +245,6 @@ TEST(AddressSanitizer, BitFieldNegativeTest) { delete Ident(x); } -TEST(AddressSanitizer, OutOfMemoryTest) { - size_t size = SANITIZER_WORDSIZE == 64 ? (size_t)(1ULL << 48) : (0xf0000000); - EXPECT_EQ(0, realloc(0, size)); - EXPECT_EQ(0, realloc(0, ~Ident(0))); - EXPECT_EQ(0, malloc(size)); - EXPECT_EQ(0, malloc(~Ident(0))); - EXPECT_EQ(0, calloc(1, size)); - EXPECT_EQ(0, calloc(1, ~Ident(0))); -} - #if ASAN_NEEDS_SEGV namespace { @@ -363,6 +371,7 @@ TEST(AddressSanitizer, ReallocFreedPointerTest) { TEST(AddressSanitizer, ReallocInvalidPointerTest) { void *ptr = Ident(malloc(42)); EXPECT_DEATH(ptr = realloc((int*)ptr + 1, 77), "attempting free.*not malloc"); + free(ptr); } TEST(AddressSanitizer, ZeroSizeMallocTest) { @@ -401,6 +410,7 @@ TEST(AddressSanitizer, MallocUsableSizeTest) { kMallocUsableSizeErrorMsg); free(array); EXPECT_DEATH(malloc_usable_size(array), kMallocUsableSizeErrorMsg); + delete int_ptr; } #endif @@ -659,7 +669,8 @@ TEST(AddressSanitizer, ThreadStackReuseTest) { PTHREAD_JOIN(t, 0); } -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i686__) || defined(__x86_64__) +#include TEST(AddressSanitizer, Store128Test) { char *a = Ident((char*)malloc(Ident(12))); char *p = a; @@ -1089,15 +1100,15 @@ TEST(AddressSanitizer, LargeStructCopyTest) { *Ident(&a) = *Ident(&a); } -ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS -static void NoAddressSafety() { +ATTRIBUTE_NO_SANITIZE_ADDRESS +static void NoSanitizeAddress() { char *foo = new char[10]; Ident(foo)[10] = 0; delete [] foo; } -TEST(AddressSanitizer, AttributeNoAddressSafetyTest) { - Ident(NoAddressSafety)(); +TEST(AddressSanitizer, AttributeNoSanitizeAddressTest) { + Ident(NoSanitizeAddress)(); } // It doesn't work on Android, as calls to new/delete go through malloc/free. @@ -1223,10 +1234,10 @@ TEST(AddressSanitizer, pthread_getschedparam) { struct sched_param param; EXPECT_DEATH( pthread_getschedparam(pthread_self(), &policy, Ident(¶m) + 2), - "AddressSanitizer: stack-buffer-overflow"); + "AddressSanitizer: stack-buffer-.*flow"); EXPECT_DEATH( pthread_getschedparam(pthread_self(), Ident(&policy) - 1, ¶m), - "AddressSanitizer: stack-buffer-overflow"); + "AddressSanitizer: stack-buffer-.*flow"); int res = pthread_getschedparam(pthread_self(), &policy, ¶m); ASSERT_EQ(0, res); } diff --git a/lib/asan/tests/asan_test_utils.h b/lib/asan/tests/asan_test_utils.h index 403773180c2f..b6bf6b82066d 100644 --- a/lib/asan/tests/asan_test_utils.h +++ b/lib/asan/tests/asan_test_utils.h @@ -41,10 +41,6 @@ #include #endif -#if defined(__i386__) || defined(__x86_64__) -#include -#endif - #ifndef __APPLE__ #include #endif -- cgit v1.2.3