Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[InstCombine][asan] Don't speculate loads before select ptr #100773

Conversation

vitalybuka
Copy link
Collaborator

@vitalybuka vitalybuka commented Jul 26, 2024

Even if memory is valid from llvm point of view,
e.g. local alloca, sanitizers have API for user
specific memory annotations.

These annotations can be used to track size of the
local object, e.g. inline vectors may prevent
accesses beyond the current vector size.

So valid programs should not access those parts of
alloca before checking preconditions.

Fixes #100639.

@llvmbot
Copy link
Collaborator

llvmbot commented Jul 26, 2024

@llvm/pr-subscribers-llvm-analysis
@llvm/pr-subscribers-compiler-rt-sanitizer

@llvm/pr-subscribers-llvm-transforms

Author: Vitaly Buka (vitalybuka)

Changes

Even if memory is valid from llvm point of view,
e.g. local alloca, sanitizers have API for user
specific memory annotations.

This annotations can be used to track size of the
local object, e.g. inline vector like may prevent
accessed beyond the current vector size.

So valid programs should not access those parts of
alloca before checking preconditions.

Fixes #100639.


Full diff: https://github.com/llvm/llvm-project/pull/100773.diff

2 Files Affected:

  • (modified) llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp (+2-2)
  • (added) llvm/test/Transforms/InstCombine/select-load.ll (+101)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
index 1661fa564c65c..ff2ea5d682142 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
@@ -1042,8 +1042,8 @@ Instruction *InstCombinerImpl::visitLoadInst(LoadInst &LI) {
   }
 
   // None of the following transforms are legal for volatile/ordered atomic
-  // loads.  Most of them do apply for unordered atomics.
-  if (!LI.isUnordered()) return nullptr;
+  // loads and sanitizers.  Most of them do apply for unordered atomics.
+  if (mustSuppressSpeculation(LI)) return nullptr;
 
   // load(gep null, ...) -> unreachable
   // load null/undef -> unreachable
diff --git a/llvm/test/Transforms/InstCombine/select-load.ll b/llvm/test/Transforms/InstCombine/select-load.ll
new file mode 100644
index 0000000000000..36883423aea36
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/select-load.ll
@@ -0,0 +1,101 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -passes=instcombine -S < %s | FileCheck %s
+
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-grtev4-linux-gnu"
+
+define i32 @test_plain(i1 %f) {
+; CHECK-LABEL: @test_plain(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 8
+; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 8
+; CHECK-NEXT:    [[A_VAL:%.*]] = load i32, ptr [[A]], align 8
+; CHECK-NEXT:    [[B_VAL:%.*]] = load i32, ptr [[B]], align 8
+; CHECK-NEXT:    [[L:%.*]] = select i1 [[F:%.*]], i32 [[A_VAL]], i32 [[B_VAL]]
+; CHECK-NEXT:    ret i32 [[L]]
+;
+entry:
+  %a = alloca i32, align 8
+  %b = alloca i32, align 8
+  %sel = select i1 %f, ptr %a, ptr %b
+  %l = load i32, ptr %sel, align 8
+  ret i32 %l
+}
+
+; Don't speculate as the condition may control which memory is valid from
+; sanitizer perspective.
+define i32 @test_asan(i1 %f) sanitize_address {
+; CHECK-LABEL: @test_asan(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 8
+; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 8
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[F:%.*]], ptr [[A]], ptr [[B]]
+; CHECK-NEXT:    [[L:%.*]] = load i32, ptr [[SEL]], align 8
+; CHECK-NEXT:    ret i32 [[L]]
+;
+entry:
+  %a = alloca i32, align 8
+  %b = alloca i32, align 8
+  %sel = select i1 %f, ptr %a, ptr %b
+  %l = load i32, ptr %sel, align 8
+  ret i32 %l
+}
+
+
+; Don't speculate as the condition may control which memory is valid from
+; sanitizer perspective.
+define i32 @test_hwasan(i1 %f) sanitize_hwaddress {
+; CHECK-LABEL: @test_hwasan(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 8
+; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 8
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[F:%.*]], ptr [[A]], ptr [[B]]
+; CHECK-NEXT:    [[L:%.*]] = load i32, ptr [[SEL]], align 8
+; CHECK-NEXT:    ret i32 [[L]]
+;
+entry:
+  %a = alloca i32, align 8
+  %b = alloca i32, align 8
+  %sel = select i1 %f, ptr %a, ptr %b
+  %l = load i32, ptr %sel, align 8
+  ret i32 %l
+}
+
+; Don't speculate as the condition may control which memory is valid from
+; sanitizer perspective.
+define i32 @test_tsan(i1 %f) sanitize_thread {
+; CHECK-LABEL: @test_tsan(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 8
+; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 8
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[F:%.*]], ptr [[A]], ptr [[B]]
+; CHECK-NEXT:    [[L:%.*]] = load i32, ptr [[SEL]], align 8
+; CHECK-NEXT:    ret i32 [[L]]
+;
+entry:
+  %a = alloca i32, align 8
+  %b = alloca i32, align 8
+  %sel = select i1 %f, ptr %a, ptr %b
+  %l = load i32, ptr %sel, align 8
+  ret i32 %l
+}
+
+; Msan just propagates shadow, even if speculated load accesses uninitialized
+; value, instrumentation will select shadow of the desired value anyway.
+define i32 @test_msan(i1 %f) sanitize_memory {
+; CHECK-LABEL: @test_msan(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 8
+; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 8
+; CHECK-NEXT:    [[A_VAL:%.*]] = load i32, ptr [[A]], align 8
+; CHECK-NEXT:    [[B_VAL:%.*]] = load i32, ptr [[B]], align 8
+; CHECK-NEXT:    [[L:%.*]] = select i1 [[F:%.*]], i32 [[A_VAL]], i32 [[B_VAL]]
+; CHECK-NEXT:    ret i32 [[L]]
+;
+entry:
+  %a = alloca i32, align 8
+  %b = alloca i32, align 8
+  %sel = select i1 %f, ptr %a, ptr %b
+  %l = load i32, ptr %sel, align 8
+  ret i32 %l
+}

@vitalybuka vitalybuka changed the base branch from users/vitalybuka/spr/main.instcombineasan-dont-speculate-loads-before-select-ptr to main July 26, 2024 17:22
@vitalybuka vitalybuka changed the base branch from main to users/vitalybuka/spr/ubsanhwasan-let-mixing-filters July 26, 2024 18:46
Base automatically changed from users/vitalybuka/spr/ubsanhwasan-let-mixing-filters to main July 26, 2024 18:54
vitalybuka added a commit that referenced this pull request Jul 26, 2024
In #100773 we will go conservative for sanitizers,
so it's better to pinpoint location consciously.

Pull Request: #100789
vitalybuka added a commit that referenced this pull request Jul 26, 2024
Even if memory is valid from `llvm` point of view,
e.g. local alloca, sanitizers have API for user
specific memory annotations.

This annotations can be used to track size of the
local object, e.g. inline vector like may prevent
accessed beyond the current vector size.

So valid programs should not access those parts of
alloca before checking preconditions.

Fixes #100639.

Pull Request: #100773
@vitalybuka vitalybuka force-pushed the users/vitalybuka/spr/instcombineasan-dont-speculate-loads-before-select-ptr branch from f8ac356 to b8cc320 Compare July 26, 2024 18:58
@vitalybuka vitalybuka changed the base branch from main to users/vitalybuka/spr/nfcload-make-scanfrom-required-parameters July 26, 2024 18:58
@vitalybuka vitalybuka force-pushed the users/vitalybuka/spr/nfcload-make-scanfrom-required-parameters branch from d61be92 to 403561b Compare July 26, 2024 18:59
@vitalybuka vitalybuka requested review from nikic and removed request for a team, antiagainst, JDevlieghere and kuhar July 26, 2024 19:00
Some optimization need to be undone with
sanitizers by #100773.

Pull Request: #100844
And extract `suppressSpeculativeLoadForSanitizers`.

Pull Request: #100794
In #100773 we will go conservative for sanitizers,
so it's better to pinpoint location consciously.

Pull Request: #100789
Even if memory is valid from `llvm` point of view,
e.g. local alloca, sanitizers have API for user
specific memory annotations.

This annotations can be used to track size of the
local object, e.g. inline vector like may prevent
accessed beyond the current vector size.

So valid programs should not access those parts of
alloca before checking preconditions.

Fixes #100639.

Pull Request: #100773
@vitalybuka vitalybuka force-pushed the users/vitalybuka/spr/nfcload-make-scanfrom-required-parameters branch from 403561b to 0fce1ba Compare July 27, 2024 00:53
@vitalybuka vitalybuka force-pushed the users/vitalybuka/spr/instcombineasan-dont-speculate-loads-before-select-ptr branch from b8cc320 to 6c404f7 Compare July 27, 2024 00:54
vitalybuka added a commit that referenced this pull request Jul 27, 2024
Some optimizations need to be undone with
sanitizers by #100773.

Pull Request: #100844
Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

vitalybuka added a commit that referenced this pull request Jul 29, 2024
In #100773 we will go conservative for sanitizers,
so it's better to pinpoint location consciously.

For #100639.
Base automatically changed from users/vitalybuka/spr/nfcload-make-scanfrom-required-parameters to main July 29, 2024 17:30
vitalybuka added a commit that referenced this pull request Jul 29, 2024
…100844)

Some optimization need to be undone with
sanitizers by #100773.

For #100639.
Created using spr 1.3.4
@vitalybuka vitalybuka merged commit 6dba99e into main Jul 29, 2024
5 of 6 checks passed
@vitalybuka vitalybuka deleted the users/vitalybuka/spr/instcombineasan-dont-speculate-loads-before-select-ptr branch July 29, 2024 18:28
banach-space pushed a commit to banach-space/llvm-project that referenced this pull request Aug 7, 2024
In llvm#100773 we will go conservative for sanitizers,
so it's better to pinpoint location consciously.

For llvm#100639.
banach-space pushed a commit to banach-space/llvm-project that referenced this pull request Aug 7, 2024
banach-space pushed a commit to banach-space/llvm-project that referenced this pull request Aug 7, 2024
…00773)

Even if memory is valid from `llvm` point of view,
e.g. local alloca, sanitizers have API for user
specific memory annotations.

These annotations can be used to track size of the
local object, e.g. inline vectors may prevent
accesses beyond the current vector size.

So valid programs should not access those parts of
alloca before checking preconditions.

Fixes llvm#100639.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[asan] Custom poisoning on stack is broken by optimizations
5 participants