diff --git a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp --- a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp @@ -191,6 +191,11 @@ cl::desc("use short granules in allocas and outlined checks"), cl::Hidden, cl::init(false), cl::ZeroOrMore); +static cl::opt ClDetectNonLinearOverflow( + "hwasan-detect-non-linear-overflow", + cl::desc("use short granules in allocas and outlined checks"), cl::Hidden, + cl::init(true)); + static cl::opt ClInstrumentPersonalityFunctions( "hwasan-instrument-personality-functions", cl::desc("instrument personality functions"), cl::Hidden, cl::init(false), @@ -773,6 +778,25 @@ if (Ptr->isSwiftError()) return true; + if (!InstrumentStack) { + // If we don't instrument the stack, don't instrument any reads that come + // from an alloca. If we are interested in detecting non-linear overflows, + // which might take the pointer outside of the stack, we will not ignore + // the access if there is any non-zero GEP. + if (findAllocaForValue(Ptr, /*OffsetZero=*/ClDetectNonLinearOverflow)) + return true; + } else { + // If we instrument the stack, do not instrument any reads that we can be + // certain are within range of an uninteresting alloca. We set OffsetZero + // to make sure no GEP can be out of range. + // + // TODO(fmayer): we could make use of some of the information we have in + // the stack safety analysis to determine whether the GEP is within range + // even if it does not have zero offset. + auto *StrictAI = findAllocaForValue(Ptr, /*OffsetZero=*/true); + if (StrictAI && !isInterestingAlloca(*StrictAI)) + return true; + } return false; } diff --git a/llvm/test/Instrumentation/HWAddressSanitizer/stack-safety-analysis.ll b/llvm/test/Instrumentation/HWAddressSanitizer/stack-safety-analysis.ll --- a/llvm/test/Instrumentation/HWAddressSanitizer/stack-safety-analysis.ll +++ b/llvm/test/Instrumentation/HWAddressSanitizer/stack-safety-analysis.ll @@ -1,6 +1,8 @@ -; RUN: opt -hwasan -hwasan-use-stack-safety=1 -hwasan-generate-tags-with-calls -S < %s | FileCheck %s --check-prefixes=SAFETY -; RUN: opt -hwasan -hwasan-use-stack-safety=0 -hwasan-generate-tags-with-calls -S < %s | FileCheck %s --check-prefixes=NOSAFETY -; RUN: opt -hwasan -hwasan-generate-tags-with-calls -S < %s | FileCheck %s --check-prefixes=SAFETY +; RUN: opt -hwasan -hwasan-instrument-with-calls -hwasan-use-stack-safety=1 -hwasan-generate-tags-with-calls -S < %s | FileCheck %s --check-prefixes=SAFETY +; RUN: opt -hwasan -hwasan-instrument-with-calls -hwasan-use-stack-safety=0 -hwasan-generate-tags-with-calls -S < %s | FileCheck %s --check-prefixes=NOSAFETY +; RUN: opt -hwasan -hwasan-instrument-with-calls -hwasan-generate-tags-with-calls -S < %s | FileCheck %s --check-prefixes=SAFETY +; RUN: opt -hwasan -hwasan-instrument-with-calls -hwasan-instrument-stack=0 -hwasan-generate-tags-with-calls -S < %s | FileCheck %s --check-prefixes=NOSTACK +; RUN: opt -hwasan -hwasan-instrument-with-calls -hwasan-detect-non-linear-overflow=0 -hwasan-instrument-stack=0 -hwasan-generate-tags-with-calls -S < %s | FileCheck %s --check-prefixes=NOSTACK_NONONLINEAR target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" target triple = "aarch64-unknown-linux-gnu" @@ -9,7 +11,11 @@ define i32 @test_load(i32* %a) sanitize_hwaddress { entry: ; NOSAFETY: call {{.*}}__hwasan_generate_tag + ; NOSAFETY: call {{.*}}__hwasan_store ; SAFETY-NOT: call {{.*}}__hwasan_generate_tag + ; SAFETY-NOT: call {{.*}}__hwasan_store + ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag + ; NOSTACK-NOT: call {{.*}}__hwasan_store %buf.sroa.0 = alloca i8, align 4 call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %buf.sroa.0) store volatile i8 0, i8* %buf.sroa.0, align 4, !tbaa !8 @@ -21,7 +27,11 @@ define i32 @test_use(i32* %a) sanitize_hwaddress { entry: ; NOSAFETY: call {{.*}}__hwasan_generate_tag + ; NOSAFETY: call {{.*}}__hwasan_store ; SAFETY: call {{.*}}__hwasan_generate_tag + ; SAFETY: call {{.*}}__hwasan_store + ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag + ; NOSTACK-NOT: call {{.*}}__hwasan_store %buf.sroa.0 = alloca i8, align 4 call void @use(i8* nonnull %buf.sroa.0) call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %buf.sroa.0) @@ -30,6 +40,26 @@ ret i32 0 } +; Check an alloca with out of range GEP to ensure it gets a tag. +define i32 @test_out_of_range(i32* %a) sanitize_hwaddress { +entry: + ; NOSAFETY: call {{.*}}__hwasan_generate_tag + ; NOSAFETY: call {{.*}}__hwasan_store + ; SAFETY: call {{.*}}__hwasan_generate_tag + ; SAFETY: call {{.*}}__hwasan_store + ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag + ; NOSTACK: call {{.*}}__hwasan_store + ; NOSTACK_NONONLINEAR-NOT: call {{.*}}__hwasan_generate_tag + ; NOSTACK_NONONLINEAR-NOT: call {{.*}}__hwasan_store + %buf.sroa.0 = alloca [10 x i8], align 4 + %off = call i32 @getoffset() + %ptr = getelementptr [10 x i8], [10 x i8]* %buf.sroa.0, i32 0, i32 %off + call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %ptr) + store volatile i8 0, i8* %ptr, align 4, !tbaa !8 + call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull %ptr) + ret i32 0 +} + ; Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) @@ -37,6 +67,7 @@ declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) declare void @use(i8* nocapture) +declare i32 @getoffset() !8 = !{!9, !9, i64 0} !9 = !{!"omnipotent char", !10, i64 0}