From af33fcdf5a46c5bd34db89615a037e5eca421ef9 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Fri, 5 Jan 2024 23:50:40 -0800 Subject: [PATCH] [asan] Enable StackSafetyAnalysis by default StackSafetyAnalysis determines whether stack-allocated variables are safe from memory access bugs and allows removing certain unneeded instrumentations. (hwasan enables StackSafetyAnalysis in https://reviews.llvm.org/D108381) Test updates: * asan-stack-safety.ll: test the -asan-use-stack-safety=1 default * lifetime-uar-uas.ll: switch to an indexed store to prevent StackSafetyAnalysis from optimizing out instrumentation for %c * alloca_vla_interact.cpp: add a load to prevent StackSafetyAnalysis from optimizing out `__asan_alloca_poison` for the VLA `array` * scariness_score_test.cpp: add -asan-use-stack-safety=0 to make a load of a `__asan_poison_memory_region`-poisoned local variable fail as intended. * other .ll tests: add -asan-use-stack-safety=0 Pull Request: https://github.com/llvm/llvm-project/pull/77210 --- .../test/asan/TestCases/alloca_vla_interact.cpp | 2 ++ .../test/asan/TestCases/scariness_score_test.cpp | 6 ++++-- .../Transforms/Instrumentation/AddressSanitizer.cpp | 2 +- .../AddressSanitizer/asan-stack-safety.ll | 2 +- .../Instrumentation/AddressSanitizer/debug_info.ll | 2 +- .../AddressSanitizer/lifetime-uar-uas.ll | 13 ++++++++----- .../Instrumentation/AddressSanitizer/lifetime.ll | 4 ++-- .../AddressSanitizer/local_stack_base.ll | 2 +- .../AddressSanitizer/stack_dynamic_alloca.ll | 8 ++++---- .../AddressSanitizer/stack_layout.ll | 4 ++-- 10 files changed, 26 insertions(+), 19 deletions(-) diff --git a/compiler-rt/test/asan/TestCases/alloca_vla_interact.cpp b/compiler-rt/test/asan/TestCases/alloca_vla_interact.cpp index 92b0afafc8db77..96ac4c7db291a0 100644 --- a/compiler-rt/test/asan/TestCases/alloca_vla_interact.cpp +++ b/compiler-rt/test/asan/TestCases/alloca_vla_interact.cpp @@ -33,6 +33,8 @@ __attribute__((noinline)) void foo(int len) { if (i) assert(!__asan_region_is_poisoned(bot, 96)); // VLA is unpoisoned at the end of iteration. volatile char array[i]; + // Ensure that asan-use-stack-safety does not optimize out the poisoning. + if (i) array[0] = 0; assert(!(reinterpret_cast(array) & 31L)); // Alloca is unpoisoned at the end of iteration, // because dominated by VLA. diff --git a/compiler-rt/test/asan/TestCases/scariness_score_test.cpp b/compiler-rt/test/asan/TestCases/scariness_score_test.cpp index d73975feb6873b..9e55e33675fde3 100644 --- a/compiler-rt/test/asan/TestCases/scariness_score_test.cpp +++ b/compiler-rt/test/asan/TestCases/scariness_score_test.cpp @@ -1,7 +1,9 @@ // Test how we produce the scariness score. // UAR Mode: runtime -// RUN: %clangxx_asan -O0 %s -o %t +// Case 26 loads a __asan_poison_memory_region-poisoned local variable, which is +// only instrumented when StackSafetyAnalysis is disabled. +// RUN: %clangxx_asan -O0 -mllvm -asan-use-stack-safety=0 %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: export %env_asan_opts=symbolize=0:detect_stack_use_after_return=1:handle_abort=1:print_scariness=1:alloc_dealloc_mismatch=1 @@ -36,7 +38,7 @@ // RUN: not %run %t 27 2>&1 | FileCheck %s --check-prefix=CHECK27 // // UAR Mode: always -// RUN: %clangxx_asan -O0 %s -o %t -fsanitize-address-use-after-return=always +// RUN: %clangxx_asan -O0 %s -o %t -fsanitize-address-use-after-return=always -mllvm -asan-use-stack-safety=0 // 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=symbolize=0:handle_abort=1:print_scariness=1:alloc_dealloc_mismatch=1 diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp index e3deafa49bd91e..5e7e08eaa9978d 100644 --- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -216,7 +216,7 @@ static cl::opt ClInstrumentWrites( cl::Hidden, cl::init(true)); static cl::opt - ClUseStackSafety("asan-use-stack-safety", cl::Hidden, cl::init(false), + ClUseStackSafety("asan-use-stack-safety", cl::Hidden, cl::init(true), cl::Hidden, cl::desc("Use Stack Safety analysis results"), cl::Optional); diff --git a/llvm/test/Instrumentation/AddressSanitizer/asan-stack-safety.ll b/llvm/test/Instrumentation/AddressSanitizer/asan-stack-safety.ll index 02c58a1f492261..8210970aaaeb4b 100644 --- a/llvm/test/Instrumentation/AddressSanitizer/asan-stack-safety.ll +++ b/llvm/test/Instrumentation/AddressSanitizer/asan-stack-safety.ll @@ -1,7 +1,7 @@ ; REQUIRES: x86-registered-target ; RUN: opt < %s -S -asan-instrumentation-with-call-threshold=0 -passes=asan -asan-use-stack-safety=0 -o - | FileCheck %s --implicit-check-not="call {{.*}} @__asan_{{load|store|stack}}" --check-prefixes=CHECK,NOSAFETY -; RUN: opt < %s -S -asan-instrumentation-with-call-threshold=0 -passes=asan -asan-use-stack-safety=1 -o - | FileCheck %s --implicit-check-not="call {{.*}} @__asan_{{load|store|stack}}" +; RUN: opt < %s -S -asan-instrumentation-with-call-threshold=0 -passes=asan | FileCheck %s --implicit-check-not="call {{.*}} @__asan_{{load|store|stack}}" ; CHECK-LABEL: define i32 @load define i32 @load() sanitize_address { diff --git a/llvm/test/Instrumentation/AddressSanitizer/debug_info.ll b/llvm/test/Instrumentation/AddressSanitizer/debug_info.ll index 4c678f984864ae..edd63c614857fe 100644 --- a/llvm/test/Instrumentation/AddressSanitizer/debug_info.ll +++ b/llvm/test/Instrumentation/AddressSanitizer/debug_info.ll @@ -1,4 +1,4 @@ -; RUN: opt < %s -passes=asan -asan-use-after-return=never -S | FileCheck %s +; RUN: opt < %s -passes=asan -asan-use-after-return=never -asan-use-stack-safety=0 -S | FileCheck %s ; Checks that llvm.dbg.declare instructions are updated ; accordingly as we merge allocas. diff --git a/llvm/test/Instrumentation/AddressSanitizer/lifetime-uar-uas.ll b/llvm/test/Instrumentation/AddressSanitizer/lifetime-uar-uas.ll index 302205c4f6cad0..a40dad526a14dc 100644 --- a/llvm/test/Instrumentation/AddressSanitizer/lifetime-uar-uas.ll +++ b/llvm/test/Instrumentation/AddressSanitizer/lifetime-uar-uas.ll @@ -11,26 +11,29 @@ target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f3 declare void @llvm.lifetime.start.p0(i64, ptr nocapture) nounwind declare void @llvm.lifetime.end.p0(i64, ptr nocapture) nounwind -define i32 @basic_test() sanitize_address { - ; CHECK-LABEL: define i32 @basic_test() +define i32 @basic_test(i64 %i) sanitize_address { + ; CHECK-LABEL: define i32 @basic_test( entry: %retval = alloca i32, align 4 - %c = alloca i8, align 1 + %c = alloca [2 x i8], align 1 ; Memory is poisoned in prologue: F1F1F1F104F3F8F2 ; CHECK-UAS: store i64 -866676825215864335, ptr %{{[0-9]+}} + ; CHECK-UAS-SS-NOT: store i64 call void @llvm.lifetime.start.p0(i64 1, ptr %c) ; Memory is unpoisoned at llvm.lifetime.start: 01 - ; CHECK-UAS: store i8 1, ptr %{{[0-9]+}} + ; CHECK-UAS: store i8 2, ptr %{{[0-9]+}} + %ci = getelementptr inbounds [2 x i8], ptr %c, i64 0, i64 %i store volatile i32 0, ptr %retval - store volatile i8 0, ptr %c, align 1 + store volatile i8 0, ptr %ci, align 1 call void @llvm.lifetime.end.p0(i64 1, ptr %c) ; Memory is poisoned at llvm.lifetime.end: F8 ; CHECK-UAS: store i8 -8, ptr %{{[0-9]+}} + ; CHECK-UAS-SS-NOT: store i8 -8, ; Unpoison memory at function exit in UAS mode. ; CHECK-UAS: store i64 0, ptr %{{[0-9]+}} diff --git a/llvm/test/Instrumentation/AddressSanitizer/lifetime.ll b/llvm/test/Instrumentation/AddressSanitizer/lifetime.ll index 7f158487a47a15..1d073cdc3bdb92 100644 --- a/llvm/test/Instrumentation/AddressSanitizer/lifetime.ll +++ b/llvm/test/Instrumentation/AddressSanitizer/lifetime.ll @@ -1,6 +1,6 @@ ; Test handling of llvm.lifetime intrinsics. -; RUN: opt < %s -passes=asan -asan-use-after-scope -asan-use-after-return=never -S | FileCheck %s --check-prefixes=CHECK,CHECK-DEFAULT -; RUN: opt < %s -passes=asan -asan-use-after-scope -asan-use-after-return=never -asan-instrument-dynamic-allocas=0 -S | FileCheck %s --check-prefixes=CHECK,CHECK-NO-DYNAMIC +; RUN: opt < %s -passes=asan -asan-use-after-scope -asan-use-after-return=never -asan-use-stack-safety=0 -S | FileCheck %s --check-prefixes=CHECK,CHECK-DEFAULT +; RUN: opt < %s -passes=asan -asan-use-after-scope -asan-use-after-return=never -asan-use-stack-safety=0 -asan-instrument-dynamic-allocas=0 -S | FileCheck %s --check-prefixes=CHECK,CHECK-NO-DYNAMIC target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" diff --git a/llvm/test/Instrumentation/AddressSanitizer/local_stack_base.ll b/llvm/test/Instrumentation/AddressSanitizer/local_stack_base.ll index 43b402e1b166f2..4e8466b685689b 100644 --- a/llvm/test/Instrumentation/AddressSanitizer/local_stack_base.ll +++ b/llvm/test/Instrumentation/AddressSanitizer/local_stack_base.ll @@ -1,4 +1,4 @@ -; RUN: opt -S -passes=asan -asan-skip-promotable-allocas=0 %s -o - | FileCheck %s +; RUN: opt -S -passes=asan -asan-use-stack-safety=0 -asan-skip-promotable-allocas=0 %s -o - | FileCheck %s ; Generated from: ; int bar(int y) { ; return y + 2; diff --git a/llvm/test/Instrumentation/AddressSanitizer/stack_dynamic_alloca.ll b/llvm/test/Instrumentation/AddressSanitizer/stack_dynamic_alloca.ll index 98851b871393c5..cbb2001c45e651 100644 --- a/llvm/test/Instrumentation/AddressSanitizer/stack_dynamic_alloca.ll +++ b/llvm/test/Instrumentation/AddressSanitizer/stack_dynamic_alloca.ll @@ -1,14 +1,14 @@ -; RUN: opt < %s -passes=asan -asan-stack-dynamic-alloca \ +; RUN: opt < %s -passes=asan -asan-stack-dynamic-alloca -asan-use-stack-safety=0 \ ; RUN: -asan-use-after-return=runtime -S | FileCheck %s \ ; RUN: --check-prefixes=CHECK,CHECK-RUNTIME -; RUN: opt < %s -passes=asan -asan-stack-dynamic-alloca -asan-mapping-scale=5 \ +; RUN: opt < %s -passes=asan -asan-stack-dynamic-alloca -asan-mapping-scale=5 -asan-use-stack-safety=0 \ ; RUN: -asan-use-after-return=runtime -S | FileCheck %s \ ; RUN: --check-prefixes=CHECK,CHECK-RUNTIME -; RUN: opt < %s -passes=asan -asan-stack-dynamic-alloca \ +; RUN: opt < %s -passes=asan -asan-stack-dynamic-alloca -asan-use-stack-safety=0 \ ; RUN: -asan-use-after-return=always -S | FileCheck %s \ ; RUN: --check-prefixes=CHECK,CHECK-ALWAYS \ ; RUN: --implicit-check-not=__asan_option_detect_stack_use_after_return -; RUN: opt < %s -passes=asan -asan-stack-dynamic-alloca \ +; RUN: opt < %s -passes=asan -asan-stack-dynamic-alloca -asan-use-stack-safety=0 \ ; RUN: -asan-use-after-return=always -S | FileCheck %s \ ; RUN: --check-prefixes=CHECK,CHECK-ALWAYS \ ; RUN: --implicit-check-not=__asan_option_detect_stack_use_after_return diff --git a/llvm/test/Instrumentation/AddressSanitizer/stack_layout.ll b/llvm/test/Instrumentation/AddressSanitizer/stack_layout.ll index 726f628607dae1..48465be36789d6 100644 --- a/llvm/test/Instrumentation/AddressSanitizer/stack_layout.ll +++ b/llvm/test/Instrumentation/AddressSanitizer/stack_layout.ll @@ -1,8 +1,8 @@ ; Test the ASan's stack layout. ; More tests in tests/Transforms/Utils/ASanStackFrameLayoutTest.cpp -; RUN: opt < %s -passes=asan -asan-stack-dynamic-alloca=0 -asan-use-after-scope -S \ +; RUN: opt < %s -passes=asan -asan-use-stack-safety=0 -asan-stack-dynamic-alloca=0 -asan-use-after-scope -S \ ; RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-STATIC -; RUN: opt < %s -passes=asan -asan-stack-dynamic-alloca=1 -asan-use-after-scope -S \ +; RUN: opt < %s -passes=asan -asan-use-stack-safety=0 -asan-stack-dynamic-alloca=1 -asan-use-after-scope -S \ ; RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-DYNAMIC target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"