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
This commit is contained in:
Kevin Athey 2021-06-08 12:45:48 -07:00
parent 8b32e25bc2
commit af8c59e06d
14 changed files with 160 additions and 18 deletions

View File

@ -198,7 +198,13 @@ static FakeStack *GetFakeStackFast() {
return GetFakeStack();
}
ALWAYS_INLINE uptr OnMalloc(uptr class_id, uptr size) {
static FakeStack *GetFakeStackFastAlways() {
if (FakeStack *fs = GetTLSFakeStack())
return fs;
return GetFakeStack();
}
static ALWAYS_INLINE uptr OnMalloc(uptr class_id, uptr size) {
FakeStack *fs = GetFakeStackFast();
if (!fs) return 0;
uptr local_stack;
@ -210,7 +216,21 @@ ALWAYS_INLINE uptr OnMalloc(uptr class_id, uptr size) {
return ptr;
}
ALWAYS_INLINE void OnFree(uptr ptr, uptr class_id, uptr size) {
static ALWAYS_INLINE uptr OnMallocAlways(uptr class_id, uptr size) {
FakeStack *fs = GetFakeStackFastAlways();
if (!fs)
return 0;
uptr local_stack;
uptr real_stack = reinterpret_cast<uptr>(&local_stack);
FakeFrame *ff = fs->Allocate(fs->stack_size_log(), class_id, real_stack);
if (!ff)
return 0; // Out of fake stack.
uptr ptr = reinterpret_cast<uptr>(ff);
SetShadow(ptr, size, class_id, 0);
return ptr;
}
static ALWAYS_INLINE void OnFree(uptr ptr, uptr class_id, uptr size) {
FakeStack::Deallocate(ptr, class_id);
SetShadow(ptr, size, class_id, kMagic8);
}
@ -228,6 +248,11 @@ using namespace __asan;
uptr ptr, uptr size) { \
OnFree(ptr, class_id, size); \
}
#define DEFINE_STACK_MALLOC_ALWAYS_WITH_CLASS_ID(class_id) \
extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr \
__asan_stack_malloc_always_##class_id(uptr size) { \
return OnMallocAlways(class_id, size); \
}
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(0)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(1)
@ -240,7 +265,23 @@ 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)
DEFINE_STACK_MALLOC_ALWAYS_WITH_CLASS_ID(0)
DEFINE_STACK_MALLOC_ALWAYS_WITH_CLASS_ID(1)
DEFINE_STACK_MALLOC_ALWAYS_WITH_CLASS_ID(2)
DEFINE_STACK_MALLOC_ALWAYS_WITH_CLASS_ID(3)
DEFINE_STACK_MALLOC_ALWAYS_WITH_CLASS_ID(4)
DEFINE_STACK_MALLOC_ALWAYS_WITH_CLASS_ID(5)
DEFINE_STACK_MALLOC_ALWAYS_WITH_CLASS_ID(6)
DEFINE_STACK_MALLOC_ALWAYS_WITH_CLASS_ID(7)
DEFINE_STACK_MALLOC_ALWAYS_WITH_CLASS_ID(8)
DEFINE_STACK_MALLOC_ALWAYS_WITH_CLASS_ID(9)
DEFINE_STACK_MALLOC_ALWAYS_WITH_CLASS_ID(10)
extern "C" {
// TODO: remove this method and fix tests that use it by setting
// -asan-use-after-return=never, after modal UAR flag lands
// (https://github.com/google/sanitizers/issues/1394)
SANITIZER_INTERFACE_ATTRIBUTE
void *__asan_get_current_fake_stack() { return GetFakeStackFast(); }

View File

@ -134,6 +134,17 @@ INTERFACE_FUNCTION(__asan_stack_malloc_7)
INTERFACE_FUNCTION(__asan_stack_malloc_8)
INTERFACE_FUNCTION(__asan_stack_malloc_9)
INTERFACE_FUNCTION(__asan_stack_malloc_10)
INTERFACE_FUNCTION(__asan_stack_malloc_always_0)
INTERFACE_FUNCTION(__asan_stack_malloc_always_1)
INTERFACE_FUNCTION(__asan_stack_malloc_always_2)
INTERFACE_FUNCTION(__asan_stack_malloc_always_3)
INTERFACE_FUNCTION(__asan_stack_malloc_always_4)
INTERFACE_FUNCTION(__asan_stack_malloc_always_5)
INTERFACE_FUNCTION(__asan_stack_malloc_always_6)
INTERFACE_FUNCTION(__asan_stack_malloc_always_7)
INTERFACE_FUNCTION(__asan_stack_malloc_always_8)
INTERFACE_FUNCTION(__asan_stack_malloc_always_9)
INTERFACE_FUNCTION(__asan_stack_malloc_always_10)
INTERFACE_FUNCTION(__asan_store1)
INTERFACE_FUNCTION(__asan_store2)
INTERFACE_FUNCTION(__asan_store4)

View 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>

View 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;

View 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>

View 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;

View 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.

View 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

View 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.
@ -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

View 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>

View File

@ -154,6 +154,8 @@ const char kAsanPtrSub[] = "__sanitizer_ptr_sub";
const char kAsanHandleNoReturnName[] = "__asan_handle_no_return";
static const int kMaxAsanStackMallocSizeClass = 10;
const char kAsanStackMallocNameTemplate[] = "__asan_stack_malloc_";
const char kAsanStackMallocAlwaysNameTemplate[] =
"__asan_stack_malloc_always_";
const char kAsanStackFreeNameTemplate[] = "__asan_stack_free_";
const char kAsanGenPrefix[] = "___asan_gen_";
const char kODRGenPrefix[] = "__odr_asan_gen_";
@ -2951,13 +2953,33 @@ bool AddressSanitizer::LooksLikeCodeInBug11395(Instruction *I) {
void FunctionStackPoisoner::initializeCallbacks(Module &M) {
IRBuilder<> IRB(*C);
for (int i = 0; i <= kMaxAsanStackMallocSizeClass; i++) {
std::string Suffix = itostr(i);
AsanStackMallocFunc[i] = M.getOrInsertFunction(
kAsanStackMallocNameTemplate + Suffix, IntptrTy, IntptrTy);
AsanStackFreeFunc[i] =
M.getOrInsertFunction(kAsanStackFreeNameTemplate + Suffix,
IRB.getVoidTy(), IntptrTy, IntptrTy);
switch (ClUseAfterReturn) {
case AsanDetectStackUseAfterReturnMode::Always:
for (int i = 0; i <= kMaxAsanStackMallocSizeClass; i++) {
std::string Suffix = itostr(i);
AsanStackMallocFunc[i] = M.getOrInsertFunction(
kAsanStackMallocAlwaysNameTemplate + Suffix, IntptrTy, IntptrTy);
AsanStackFreeFunc[i] =
M.getOrInsertFunction(kAsanStackFreeNameTemplate + Suffix,
IRB.getVoidTy(), IntptrTy, IntptrTy);
}
break;
case AsanDetectStackUseAfterReturnMode::Runtime:
for (int i = 0; i <= kMaxAsanStackMallocSizeClass; i++) {
std::string Suffix = itostr(i);
AsanStackMallocFunc[i] = M.getOrInsertFunction(
kAsanStackMallocNameTemplate + Suffix, IntptrTy, IntptrTy);
AsanStackFreeFunc[i] =
M.getOrInsertFunction(kAsanStackFreeNameTemplate + Suffix,
IRB.getVoidTy(), IntptrTy, IntptrTy);
}
break;
case AsanDetectStackUseAfterReturnMode::Never:
// Do Nothing
break;
case AsanDetectStackUseAfterReturnMode::Invalid:
// Do Nothing
break;
}
if (ASan.UseAfterScope) {
AsanPoisonStackMemoryFunc = M.getOrInsertFunction(

View File

@ -103,7 +103,7 @@ define void @Simple() uwtable sanitize_address {
; ALWAYS-LABEL: @Simple(
; ALWAYS-NEXT: entry:
; ALWAYS-NEXT: [[ASAN_LOCAL_STACK_BASE:%.*]] = alloca i64, align 8
; ALWAYS-NEXT: [[TMP0:%.*]] = call i64 @__asan_stack_malloc_0(i64 64)
; ALWAYS-NEXT: [[TMP0:%.*]] = call i64 @__asan_stack_malloc_always_0(i64 64)
; ALWAYS-NEXT: [[TMP1:%.*]] = icmp eq i64 [[TMP0]], 0
; ALWAYS-NEXT: br i1 [[TMP1]], label [[TMP2:%.*]], label [[TMP4:%.*]]
; ALWAYS: 2:

View File

@ -1,10 +1,10 @@
; RUN: opt < %s -asan -asan-module -enable-new-pm=0 -asan-use-after-return=never -S | FileCheck --check-prefix=CHECK-PLAIN %s
; RUN: opt < %s -passes='asan-pipeline' -asan-use-after-return=never -S | FileCheck --check-prefix=CHECK-PLAIN %s
; RUN: opt < %s -asan -asan-module -enable-new-pm=0 -asan-use-after-return=never -S | FileCheck --check-prefix=CHECK-PLAIN --implicit-check-not=__asan_stack_malloc %s
; RUN: opt < %s -passes='asan-pipeline' -asan-use-after-return=never -S | FileCheck --check-prefix=CHECK-PLAIN --implicit-check-not=__asan_stack_malloc %s
; RUN: opt < %s -asan -asan-module -enable-new-pm=0 -asan-use-after-return=runtime -S | FileCheck --check-prefixes=CHECK-UAR,CHECK-UAR-RUNTIME %s
; RUN: opt < %s -passes='asan-pipeline' -asan-use-after-return=runtime -S | FileCheck --check-prefixes=CHECK-UAR,CHECK-UAR-RUNTIME %s
; RUN: opt < %s -asan -asan-module -enable-new-pm=0 -asan-use-after-return=always -S \
; RUN: | FileCheck --check-prefixes=CHECK-UAR --implicit-check-not=__asan_option_detect_stack_use_after_return %s
; RUN: opt < %s -passes='asan-pipeline' -asan-use-after-return=always -S | FileCheck --check-prefix=CHECK-UAR %s
; RUN: opt < %s -passes='asan-pipeline' -asan-use-after-return=always -S | FileCheck --check-prefixes=CHECK-UAR,CHECK-UAR-ALWAYS %s
target datalayout = "e-i64:64-f80:128-s:64-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
@ -19,7 +19,8 @@ entry:
; CHECK-UAR-LABEL: Bar
; CHECK-UAR-RUNTIME: load i32, i32* @__asan_option_detect_stack_use_after_return
; CHECK-UAR-RUNTIME: label
; CHECK-UAR: call i64 @__asan_stack_malloc_4
; CHECK-UAR-RUNTIME: call i64 @__asan_stack_malloc_4
; CHECK-UAR-ALWAYS: call i64 @__asan_stack_malloc_always_4
; CHECK-UAR-RUNTIME: label
; Poison red zones.
; CHECK-UAR: store i64 -1007680412564983311

View File

@ -31,7 +31,8 @@ entry:
; COM: CHECK-NORUNTIME-NOT: load i32, i32* @__asan_option_detect_stack_use_after_return
; CHECK-RUNTIME: [[UAR_ENABLED_BB:^[0-9]+]]:
; CHECK: [[FAKE_STACK_RT:%[0-9]+]] = call i64 @__asan_stack_malloc_
; CHECK-RUNTIME: [[FAKE_STACK_RT:%[0-9]+]] = call i64 @__asan_stack_malloc_
; CHECK-ALWAYS: [[FAKE_STACK_RT:%[0-9]+]] = call i64 @__asan_stack_malloc_always_
; CHECK-RUNTIME: [[FAKE_STACK_BB:^[0-9]+]]:
; CHECK-RUNTIME: [[FAKE_STACK:%[0-9]+]] = phi i64 [ 0, %entry ], [ [[FAKE_STACK_RT]], %[[UAR_ENABLED_BB]] ]