Update and improve compiler-rt tests for -mllvm -asan_use_after_return=(never|[runtim...
authorKevin Athey <kda@google.com>
Fri, 4 Jun 2021 21:30:04 +0000 (14:30 -0700)
committerKevin Athey <kda@google.com>
Fri, 4 Jun 2021 23:30:47 +0000 (16:30 -0700)
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

13 files changed:
compiler-rt/lib/asan/asan_interface.inc
compiler-rt/lib/asan/asan_rtl.cpp
compiler-rt/lib/asan/weak_symbols.txt
compiler-rt/test/asan/TestCases/Linux/uar_signals.cpp
compiler-rt/test/asan/TestCases/Posix/stack-use-after-return.cpp
compiler-rt/test/asan/TestCases/Windows/dll_stack_use_after_return.cpp
compiler-rt/test/asan/TestCases/Windows/stack_use_after_return.cpp
compiler-rt/test/asan/TestCases/heavy_uar_test.cpp
compiler-rt/test/asan/TestCases/pass-struct-byval-uar.cpp
compiler-rt/test/asan/TestCases/scariness_score_test.cpp
compiler-rt/test/asan/TestCases/uar_and_exceptions.cpp
llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
llvm/test/Instrumentation/AddressSanitizer/fake-stack.ll

index 9480104..997d5c1 100644 (file)
@@ -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)
index e715d77..685ce03 100644 (file)
 #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();
 
index fe680f8..8d66f11 100644 (file)
@@ -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
index f96a2fe..71671e6 100644 (file)
@@ -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 <signal.h>
 #include <stdlib.h>
index bb7f843..1deee8f 100644 (file)
@@ -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;
index 3f36fcc..9c8095c 100644 (file)
@@ -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 <malloc.h>
 
index 9773084..bdeba17 100644 (file)
@@ -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;
 
index a203174..3a615fe 100644 (file)
@@ -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.
index aa6fa57..650a5de 100644 (file)
@@ -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
index b601225..2c6ae85 100644 (file)
@@ -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.
 // 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
index 2357ae8..b3a8fb4 100644 (file)
@@ -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 <stdio.h>
 
index 82e8fb4..c64539a 100644 (file)
@@ -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;
 }
 
index 9a17a54..d50743b 100644 (file)
@@ -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 {