From 60e5243e593ec7e0feca42783edb735e9ac2c4a7 Mon Sep 17 00:00:00 2001 From: Kevin Athey Date: Fri, 4 Jun 2021 14:30:04 -0700 Subject: [PATCH] Update and improve compiler-rt tests for -mllvm -asan_use_after_return=(never|[runtime]|always). In addition: - optionally add global flag to capture compile intent for UAR: __asan_detect_use_after_return_always. The global is a SANITIZER_WEAK_ATTRIBUTE. for issue: https://github.com/google/sanitizers/issues/1394 Reviewed By: vitalybuka Differential Revision: https://reviews.llvm.org/D103304 --- compiler-rt/lib/asan/asan_interface.inc | 1 + compiler-rt/lib/asan/asan_rtl.cpp | 28 +++++++++++++-- compiler-rt/lib/asan/weak_symbols.txt | 1 + .../test/asan/TestCases/Linux/uar_signals.cpp | 2 ++ .../Posix/stack-use-after-return.cpp | 22 ++++++++++-- .../Windows/dll_stack_use_after_return.cpp | 2 ++ .../Windows/stack_use_after_return.cpp | 2 ++ .../test/asan/TestCases/heavy_uar_test.cpp | 2 ++ .../asan/TestCases/pass-struct-byval-uar.cpp | 4 +++ .../asan/TestCases/scariness_score_test.cpp | 36 +++++++++++++++++++ .../asan/TestCases/uar_and_exceptions.cpp | 2 ++ .../Instrumentation/AddressSanitizer.cpp | 12 +++++++ .../AddressSanitizer/fake-stack.ll | 7 ++-- 13 files changed, 113 insertions(+), 8 deletions(-) diff --git a/compiler-rt/lib/asan/asan_interface.inc b/compiler-rt/lib/asan/asan_interface.inc index 948010439827..997d5c126c71 100644 --- a/compiler-rt/lib/asan/asan_interface.inc +++ b/compiler-rt/lib/asan/asan_interface.inc @@ -14,6 +14,7 @@ INTERFACE_FUNCTION(__asan_alloca_poison) INTERFACE_FUNCTION(__asan_allocas_unpoison) INTERFACE_FUNCTION(__asan_before_dynamic_init) INTERFACE_FUNCTION(__asan_describe_address) +INTERFACE_FUNCTION(__asan_detect_use_after_return_always) INTERFACE_FUNCTION(__asan_exp_load1) INTERFACE_FUNCTION(__asan_exp_load2) INTERFACE_FUNCTION(__asan_exp_load4) diff --git a/compiler-rt/lib/asan/asan_rtl.cpp b/compiler-rt/lib/asan/asan_rtl.cpp index e715d7742289..685ce03b69d0 100644 --- a/compiler-rt/lib/asan/asan_rtl.cpp +++ b/compiler-rt/lib/asan/asan_rtl.cpp @@ -23,11 +23,12 @@ #include "asan_stats.h" #include "asan_suppressions.h" #include "asan_thread.h" +#include "lsan/lsan_common.h" #include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_flags.h" +#include "sanitizer_common/sanitizer_internal_defs.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_symbolizer.h" -#include "lsan/lsan_common.h" #include "ubsan/ubsan_init.h" #include "ubsan/ubsan_platform.h" @@ -35,6 +36,17 @@ uptr __asan_shadow_memory_dynamic_address; // Global interface symbol. int __asan_option_detect_stack_use_after_return; // Global interface symbol. uptr *__asan_test_only_reported_buggy_pointer; // Used only for testing asan. +#if !SANITIZER_WINDOWS +// Instrumented code can set this value in terms of -asan_use_after_return +// * __asan_detect_use_after_return_always is undefined: all instrumented +// modules either compiled with asan_use_after_return 1 (runtime) or 0 +// (never) +// * __asan_detect_use_after_return_always is defined: at least one of modules +// compiled with asan_use_after_return 2 (always) +extern "C" SANITIZER_WEAK_ATTRIBUTE const int + __asan_detect_use_after_return_always; +#endif // !SANITIZER_WINDOWS + namespace __asan { uptr AsanMappingProfile[kAsanMappingProfileSize]; @@ -386,6 +398,17 @@ static bool UNUSED __local_asan_dyninit = [] { }(); #endif +static void InitAsanOptionDetectStackUseAfterReturn() { + __asan_option_detect_stack_use_after_return = + flags()->detect_stack_use_after_return; + if (!SANITIZER_WINDOWS) { + if (&__asan_detect_use_after_return_always) { + CHECK_EQ(1, __asan_detect_use_after_return_always); + __asan_option_detect_stack_use_after_return = 1; + } + } +} + static void AsanInitInternal() { if (LIKELY(asan_inited)) return; SanitizerToolName = "AddressSanitizer"; @@ -427,8 +450,7 @@ static void AsanInitInternal() { __sanitizer_set_report_path(common_flags()->log_path); - __asan_option_detect_stack_use_after_return = - flags()->detect_stack_use_after_return; + InitAsanOptionDetectStackUseAfterReturn(); __sanitizer::InitializePlatformEarly(); diff --git a/compiler-rt/lib/asan/weak_symbols.txt b/compiler-rt/lib/asan/weak_symbols.txt index fe680f8a9a4f..8d66f114aaa6 100644 --- a/compiler-rt/lib/asan/weak_symbols.txt +++ b/compiler-rt/lib/asan/weak_symbols.txt @@ -1,5 +1,6 @@ ___asan_default_options ___asan_default_suppressions +___asan_detect_use_after_return_always ___asan_on_error ___asan_set_shadow_00 ___asan_set_shadow_f1 diff --git a/compiler-rt/test/asan/TestCases/Linux/uar_signals.cpp b/compiler-rt/test/asan/TestCases/Linux/uar_signals.cpp index f96a2fecb367..71671e66b577 100644 --- a/compiler-rt/test/asan/TestCases/Linux/uar_signals.cpp +++ b/compiler-rt/test/asan/TestCases/Linux/uar_signals.cpp @@ -1,6 +1,8 @@ // This test checks that the implementation of use-after-return // is async-signal-safe. // RUN: %clangxx_asan -std=c++11 -O1 %s -o %t -pthread && %run %t +// RUN: %clangxx_asan -std=c++11 -O1 %s -o %t -pthread -mllvm -asan-use-after-return=never && %run %t +// RUN: %clangxx_asan -std=c++11 -O1 %s -o %t -pthread -mllvm -asan-use-after-return=always && %run %t // REQUIRES: stable-runtime #include #include diff --git a/compiler-rt/test/asan/TestCases/Posix/stack-use-after-return.cpp b/compiler-rt/test/asan/TestCases/Posix/stack-use-after-return.cpp index bb7f84309384..1deee8f1cd39 100644 --- a/compiler-rt/test/asan/TestCases/Posix/stack-use-after-return.cpp +++ b/compiler-rt/test/asan/TestCases/Posix/stack-use-after-return.cpp @@ -3,16 +3,32 @@ // RUN: %clangxx_asan -O2 %s -pthread -o %t && %env_asan_opts=detect_stack_use_after_return=1 not %run %t 2>&1 | FileCheck %s // RUN: %clangxx_asan -O3 %s -pthread -o %t && %env_asan_opts=detect_stack_use_after_return=1 not %run %t 2>&1 | FileCheck %s // RUN: %env_asan_opts=detect_stack_use_after_return=0 %run %t +// RUN: %clangxx_asan -O0 %s -pthread -o %t -mllvm -asan-use-after-return=always && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %s -pthread -o %t -mllvm -asan-use-after-return=always && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -pthread -o %t -mllvm -asan-use-after-return=always && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -pthread -o %t -mllvm -asan-use-after-return=always && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -pthread -o %t -mllvm -asan-use-after-return=never && %run %t // Regression test for a CHECK failure with small stack size and large frame. // RUN: %clangxx_asan -O3 %s -pthread -o %t -DkSize=10000 -DUseThread -DkStackSize=131072 && %env_asan_opts=detect_stack_use_after_return=1 not %run %t 2>&1 | FileCheck --check-prefix=THREAD %s +// RUN: %clangxx_asan -O3 %s -pthread -o %t -DkSize=10000 -DUseThread -DkStackSize=131072 -mllvm -asan-use-after-return=always && not %run %t 2>&1 | FileCheck --check-prefix=THREAD %s // -// Test that we can find UAR in a thread other than main: +// Test that we can find UAR in a thread other than main (UAR mode: runtime): // RUN: %clangxx_asan -DUseThread -O2 %s -pthread -o %t && %env_asan_opts=detect_stack_use_after_return=1 not %run %t 2>&1 | FileCheck --check-prefix=THREAD %s // // Test the max_uar_stack_size_log/min_uar_stack_size_log flag. +// (uses the previous) // // RUN: %env_asan_opts=detect_stack_use_after_return=1:max_uar_stack_size_log=20:verbosity=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-20 %s // RUN: %env_asan_opts=detect_stack_use_after_return=1:min_uar_stack_size_log=24:max_uar_stack_size_log=24:verbosity=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-24 %s +// +// Test that we can find UAR in a thread other than main (UAR mode: always): +// RUN: %clangxx_asan -DUseThread -O2 %s -pthread -o %t -mllvm -asan-use-after-return=always && not %run %t 2>&1 | FileCheck --check-prefix=THREAD %s +// +// Test the max_uar_stack_size_log/min_uar_stack_size_log flag. +// (uses the previous) +// +// RUN: %env_asan_opts=max_uar_stack_size_log=20:verbosity=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-20 %s +// RUN: %env_asan_opts=min_uar_stack_size_log=24:max_uar_stack_size_log=24:verbosity=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-24 %s // This test runs out of stack on AArch64. // UNSUPPORTED: aarch64 @@ -89,7 +105,7 @@ int main(int argc, char **argv) { fprintf(stderr, "pthread_attr_setstacksize returned %d\n", ret); abort(); } - + size_t stacksize_check; ret = pthread_attr_getstacksize(&attr, &stacksize_check); if (ret != 0) { @@ -100,7 +116,7 @@ int main(int argc, char **argv) { if (stacksize_check != desired_stack_size) { fprintf(stderr, "Unable to set stack size to %d, the stack size is %d.\n", (int)desired_stack_size, (int)stacksize_check); - abort(); + abort(); } } pthread_t t; diff --git a/compiler-rt/test/asan/TestCases/Windows/dll_stack_use_after_return.cpp b/compiler-rt/test/asan/TestCases/Windows/dll_stack_use_after_return.cpp index 3f36fccb0a76..9c8095cd5fbc 100644 --- a/compiler-rt/test/asan/TestCases/Windows/dll_stack_use_after_return.cpp +++ b/compiler-rt/test/asan/TestCases/Windows/dll_stack_use_after_return.cpp @@ -1,6 +1,8 @@ // RUN: %clang_cl_asan -Od %p/dll_host.cpp -Fe%t // RUN: %clang_cl_asan -LD -Od %s -Fe%t.dll // RUN: %env_asan_opts=detect_stack_use_after_return=1 not %run %t %t.dll 2>&1 | FileCheck %s +// RUN: %clang_cl_asan -LD -Od %s -Fe%t.dll -mllvm -asan-use-after-return=always +// RUN: not %run %t %t.dll 2>&1 | FileCheck %s #include diff --git a/compiler-rt/test/asan/TestCases/Windows/stack_use_after_return.cpp b/compiler-rt/test/asan/TestCases/Windows/stack_use_after_return.cpp index 9773084f81af..bdeba17dd4f5 100644 --- a/compiler-rt/test/asan/TestCases/Windows/stack_use_after_return.cpp +++ b/compiler-rt/test/asan/TestCases/Windows/stack_use_after_return.cpp @@ -1,5 +1,7 @@ // RUN: %clang_cl_asan -Od %s -Fe%t // RUN: %env_asan_opts=detect_stack_use_after_return=1 not %run %t 2>&1 | FileCheck %s +// RUN: %clang_cl_asan -Od %s -Fe%t -mllvm -asan-use-after-return=always +// RUN: not %run %t 2>&1 | FileCheck %s char *x; diff --git a/compiler-rt/test/asan/TestCases/heavy_uar_test.cpp b/compiler-rt/test/asan/TestCases/heavy_uar_test.cpp index a203174e0ae0..3a615fea476d 100644 --- a/compiler-rt/test/asan/TestCases/heavy_uar_test.cpp +++ b/compiler-rt/test/asan/TestCases/heavy_uar_test.cpp @@ -1,5 +1,7 @@ // RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=detect_stack_use_after_return=1 not %run %t 2>&1 | FileCheck %s // RUN: %clangxx_asan -O2 %s -o %t && %env_asan_opts=detect_stack_use_after_return=1 not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O0 %s -o %t -mllvm -asan-use-after-return=always && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -o %t -mllvm -asan-use-after-return=always && not %run %t 2>&1 | FileCheck %s // XFAIL: windows-msvc // FIXME: Fix this test under GCC. diff --git a/compiler-rt/test/asan/TestCases/pass-struct-byval-uar.cpp b/compiler-rt/test/asan/TestCases/pass-struct-byval-uar.cpp index aa6fa579e183..650a5de89bea 100644 --- a/compiler-rt/test/asan/TestCases/pass-struct-byval-uar.cpp +++ b/compiler-rt/test/asan/TestCases/pass-struct-byval-uar.cpp @@ -4,6 +4,10 @@ // RUN: FileCheck --check-prefix=CHECK-NO-UAR %s // RUN: not %env_asan_opts=detect_stack_use_after_return=1 %run %t 2>&1 | \ // RUN: FileCheck --check-prefix=CHECK-UAR %s +// RUN: %clangxx_asan -O0 %s -o %t -mllvm -asan-use-after-return=never && \ +// RUN: %run %t 2>&1 | FileCheck --check-prefix=CHECK-NO-UAR %s +// RUN: %clangxx_asan -O0 %s -o %t -mllvm -asan-use-after-return=always && \ +// RUN: not %run %t 2>&1 | FileCheck --check-prefix=CHECK-UAR %s // // On several architectures, the IR does not use byval arguments for foo() and // instead creates a copy in main() and gives foo() a pointer to the copy. In diff --git a/compiler-rt/test/asan/TestCases/scariness_score_test.cpp b/compiler-rt/test/asan/TestCases/scariness_score_test.cpp index b60122541cc3..2c6ae85fc27e 100644 --- a/compiler-rt/test/asan/TestCases/scariness_score_test.cpp +++ b/compiler-rt/test/asan/TestCases/scariness_score_test.cpp @@ -1,5 +1,6 @@ // Test how we produce the scariness score. +// UAR Mode: runtime // RUN: %clangxx_asan -O0 %s -o %t // On OSX and Windows, alloc_dealloc_mismatch=1 isn't 100% reliable, so it's // off by default. It's safe for these tests, though, so we turn it on. @@ -33,6 +34,41 @@ // RUN: not %run %t 25 2>&1 | FileCheck %s --check-prefix=CHECK25 // RUN: not %run %t 26 2>&1 | FileCheck %s --check-prefix=CHECK26 // RUN: not %run %t 27 2>&1 | FileCheck %s --check-prefix=CHECK27 +// +// UAR Mode: always +// RUN: %clangxx_asan -O0 %s -o %t -mllvm -asan-use-after-return=always +// On OSX and Windows, alloc_dealloc_mismatch=1 isn't 100% reliable, so it's +// off by default. It's safe for these tests, though, so we turn it on. +// RUN: export %env_asan_opts=handle_abort=1:print_scariness=1:alloc_dealloc_mismatch=1 +// Make sure the stack is limited (may not be the default under GNU make) +// RUN: ulimit -s 4096 +// RUN: not %run %t 1 2>&1 | FileCheck %s --check-prefix=CHECK1 +// RUN: not %run %t 2 2>&1 | FileCheck %s --check-prefix=CHECK2 +// RUN: not %run %t 3 2>&1 | FileCheck %s --check-prefix=CHECK3 +// RUN: not %run %t 4 2>&1 | FileCheck %s --check-prefix=CHECK4 +// RUN: not %run %t 5 2>&1 | FileCheck %s --check-prefix=CHECK5 +// RUN: not %run %t 6 2>&1 | FileCheck %s --check-prefix=CHECK6 +// RUN: not %run %t 7 2>&1 | FileCheck %s --check-prefix=CHECK7 +// RUN: not %run %t 8 2>&1 | FileCheck %s --check-prefix=CHECK8 +// RUN: not %run %t 9 2>&1 | FileCheck %s --check-prefix=CHECK9 +// RUN: not %run %t 10 2>&1 | FileCheck %s --check-prefix=CHECK10 +// RUN: not %run %t 11 2>&1 | FileCheck %s --check-prefix=CHECK11 +// RUN: not %run %t 12 2>&1 | FileCheck %s --check-prefix=CHECK12 +// RUN: not %run %t 13 2>&1 | FileCheck %s --check-prefix=CHECK13 +// RUN: not %run %t 14 2>&1 | FileCheck %s --check-prefix=CHECK14 +// RUN: not %run %t 15 2>&1 | FileCheck %s --check-prefix=CHECK15 +// RUN: not %run %t 16 2>&1 | FileCheck %s --check-prefix=CHECK16 +// RUN: not %run %t 17 2>&1 | FileCheck %s --check-prefix=CHECK17 +// RUN: not %run %t 18 2>&1 | FileCheck %s --check-prefix=CHECK18 +// RUN: not %run %t 19 2>&1 | FileCheck %s --check-prefix=CHECK19 +// RUN: not %run %t 20 2>&1 | FileCheck %s --check-prefix=CHECK20 +// RUN: not %run %t 21 2>&1 | FileCheck %s --check-prefix=CHECK21 +// RUN: not %run %t 22 2>&1 | FileCheck %s --check-prefix=CHECK22 +// RUN: not %run %t 23 2>&1 | FileCheck %s --check-prefix=CHECK23 +// RUN: not %run %t 24 2>&1 | FileCheck %s --check-prefix=CHECK24 +// RUN: not %run %t 25 2>&1 | FileCheck %s --check-prefix=CHECK25 +// RUN: not %run %t 26 2>&1 | FileCheck %s --check-prefix=CHECK26 +// RUN: not %run %t 27 2>&1 | FileCheck %s --check-prefix=CHECK27 // Parts of the test are too platform-specific: // REQUIRES: x86_64-target-arch // REQUIRES: shell diff --git a/compiler-rt/test/asan/TestCases/uar_and_exceptions.cpp b/compiler-rt/test/asan/TestCases/uar_and_exceptions.cpp index 2357ae803ac2..b3a8fb476d3d 100644 --- a/compiler-rt/test/asan/TestCases/uar_and_exceptions.cpp +++ b/compiler-rt/test/asan/TestCases/uar_and_exceptions.cpp @@ -1,6 +1,8 @@ // Test that use-after-return works with exceptions. // RUN: %clangxx_asan -O0 %s -o %t // RUN: %env_asan_opts=detect_stack_use_after_return=1 %run %t +// RUN: %clangxx_asan -O0 %s -o %t -mllvm -asan-use-after-return=always +// RUN: %run %t #include diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp index 82e8fb448920..c64539a8fb98 100644 --- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -2645,6 +2645,18 @@ bool ModuleAddressSanitizer::instrumentModule(Module &M) { appendToGlobalDtors(M, AsanDtorFunction, Priority); } +#if !SANITIZER_WINDOWS + assert(ClUseAfterReturn != AsanDetectStackUseAfterReturnMode::Invalid); + if (ClUseAfterReturn == AsanDetectStackUseAfterReturnMode::Always) { + Type *IntTy = Type::getInt32Ty(*C); + M.getOrInsertGlobal("__asan_detect_use_after_return_always", IntTy, [&] { + return new GlobalVariable( + M, IntTy, /*isConstant=*/true, GlobalValue::WeakODRLinkage, + ConstantInt::get(IntTy, 1), "__asan_detect_use_after_return_always"); + }); + } +#endif // !SANITIZER_WINDOWS + return true; } diff --git a/llvm/test/Instrumentation/AddressSanitizer/fake-stack.ll b/llvm/test/Instrumentation/AddressSanitizer/fake-stack.ll index 9a17a542f717..d50743b5c2fa 100644 --- a/llvm/test/Instrumentation/AddressSanitizer/fake-stack.ll +++ b/llvm/test/Instrumentation/AddressSanitizer/fake-stack.ll @@ -1,10 +1,13 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes='asan-pipeline' -asan-use-after-return=0 -S | FileCheck %s --check-prefixes=CHECK,NEVER -; RUN: opt < %s -passes='asan-pipeline' -asan-use-after-return=1 -S | FileCheck %s --check-prefixes=CHECK,RUNTIME +; RUN: opt < %s -passes='asan-pipeline' -asan-use-after-return=0 -S | FileCheck %s --check-prefixes=CHECK,NEVER --implicit-check-not=__asan_detect_use_after_return_always +; RUN: opt < %s -passes='asan-pipeline' -asan-use-after-return=1 -S | FileCheck %s --check-prefixes=CHECK,RUNTIME --implicit-check-not=__asan_detect_use_after_return_always ; RUN: opt < %s -passes='asan-pipeline' -asan-use-after-return=2 -S | FileCheck %s --check-prefixes=CHECK,ALWAYS target datalayout = "e-i64:64-f80:128-s:64-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" +; ALWAYS-LABEL: @__asan_detect_use_after_return_always = +; ALWAYS-SAME: weak_odr constant i32 1 + declare void @Foo(i8*) define void @Empty() uwtable sanitize_address {