Skip to content

Commit 6dba99e

Browse files
authored
[InstCombine][asan] Don't speculate loads before select ptr (llvm#100773)
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.
1 parent f9e7cba commit 6dba99e

File tree

8 files changed

+79
-32
lines changed

8 files changed

+79
-32
lines changed

llvm/lib/Analysis/Loads.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -378,8 +378,12 @@ bool llvm::isSafeToLoadUnconditionally(Value *V, Align Alignment, const APInt &S
378378
// If DT is not specified we can't make context-sensitive query
379379
const Instruction* CtxI = DT ? ScanFrom : nullptr;
380380
if (isDereferenceableAndAlignedPointer(V, Alignment, Size, DL, CtxI, AC, DT,
381-
TLI))
382-
return true;
381+
TLI)) {
382+
// With sanitizers `Dereferenceable` is not always enough for unconditional
383+
// load.
384+
if (!ScanFrom || !suppressSpeculativeLoadForSanitizers(*ScanFrom))
385+
return true;
386+
}
383387

384388
if (!ScanFrom)
385389
return false;

llvm/test/Transforms/InstCombine/load.ll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,11 @@ define i32 @test5(i1 %C) {
5656
ret i32 %Z
5757
}
5858

59+
; FIXME: Constants should be allowed for this optimization.
5960
define i32 @test5_asan(i1 %C) sanitize_address {
6061
; CHECK-LABEL: @test5_asan(
61-
; CHECK-NEXT: [[Z:%.*]] = select i1 [[C:%.*]], i32 42, i32 47
62+
; CHECK-NEXT: [[Y:%.*]] = select i1 [[C:%.*]], ptr @X, ptr @X2
63+
; CHECK-NEXT: [[Z:%.*]] = load i32, ptr [[Y]], align 4
6264
; CHECK-NEXT: ret i32 [[Z]]
6365
;
6466
%Y = select i1 %C, ptr @X, ptr @X2 ; <ptr> [#uses=1]

llvm/test/Transforms/InstCombine/ptr-replace-alloca.ll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,9 @@ entry:
430430
define i8 @select_diff_addrspace_remove_alloca_asan(i1 %cond, ptr %p) sanitize_address {
431431
; CHECK-LABEL: @select_diff_addrspace_remove_alloca_asan(
432432
; CHECK-NEXT: entry:
433-
; CHECK-NEXT: ret i8 0
433+
; CHECK-NEXT: [[GEP2:%.*]] = select i1 [[COND:%.*]], ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) @g2, i64 4), ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) @g2, i64 6)
434+
; CHECK-NEXT: [[LOAD:%.*]] = load i8, ptr addrspace(1) [[GEP2]], align 1
435+
; CHECK-NEXT: ret i8 [[LOAD]]
434436
;
435437
entry:
436438
%alloca = alloca [32 x i8]

llvm/test/Transforms/InstCombine/select-load.ll

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,8 @@ define i32 @test_asan(i1 %f) sanitize_address {
2929
; CHECK-NEXT: entry:
3030
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 8
3131
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 8
32-
; CHECK-NEXT: [[A_VAL:%.*]] = load i32, ptr [[A]], align 8
33-
; CHECK-NEXT: [[B_VAL:%.*]] = load i32, ptr [[B]], align 8
34-
; CHECK-NEXT: [[L:%.*]] = select i1 [[F:%.*]], i32 [[A_VAL]], i32 [[B_VAL]]
32+
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[F:%.*]], ptr [[A]], ptr [[B]]
33+
; CHECK-NEXT: [[L:%.*]] = load i32, ptr [[SEL]], align 8
3534
; CHECK-NEXT: ret i32 [[L]]
3635
;
3736
entry:
@@ -50,9 +49,8 @@ define i32 @test_hwasan(i1 %f) sanitize_hwaddress {
5049
; CHECK-NEXT: entry:
5150
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 8
5251
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 8
53-
; CHECK-NEXT: [[A_VAL:%.*]] = load i32, ptr [[A]], align 8
54-
; CHECK-NEXT: [[B_VAL:%.*]] = load i32, ptr [[B]], align 8
55-
; CHECK-NEXT: [[L:%.*]] = select i1 [[F:%.*]], i32 [[A_VAL]], i32 [[B_VAL]]
52+
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[F:%.*]], ptr [[A]], ptr [[B]]
53+
; CHECK-NEXT: [[L:%.*]] = load i32, ptr [[SEL]], align 8
5654
; CHECK-NEXT: ret i32 [[L]]
5755
;
5856
entry:
@@ -70,9 +68,8 @@ define i32 @test_tsan(i1 %f) sanitize_thread {
7068
; CHECK-NEXT: entry:
7169
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 8
7270
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 8
73-
; CHECK-NEXT: [[A_VAL:%.*]] = load i32, ptr [[A]], align 8
74-
; CHECK-NEXT: [[B_VAL:%.*]] = load i32, ptr [[B]], align 8
75-
; CHECK-NEXT: [[L:%.*]] = select i1 [[F:%.*]], i32 [[A_VAL]], i32 [[B_VAL]]
71+
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[F:%.*]], ptr [[A]], ptr [[B]]
72+
; CHECK-NEXT: [[L:%.*]] = load i32, ptr [[SEL]], align 8
7673
; CHECK-NEXT: ret i32 [[L]]
7774
;
7875
entry:

llvm/test/Transforms/InstCombine/strnlen-2.ll

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,14 @@ define i64 @fold_strnlen_s3_s5_1(i1 %C) {
3838
ret i64 %len
3939
}
4040

41+
; FIXME: Constants should be allowed for this optimization.
4142
define i64 @fold_strnlen_s3_s5_1_asan(i1 %C) sanitize_address {
4243
; CHECK-LABEL: @fold_strnlen_s3_s5_1_asan(
43-
; CHECK-NEXT: ret i64 1
44+
; CHECK-NEXT: [[PTR:%.*]] = select i1 [[C:%.*]], ptr @s3, ptr @s6
45+
; CHECK-NEXT: [[STRNLEN_CHAR0:%.*]] = load i8, ptr [[PTR]], align 1
46+
; CHECK-NEXT: [[STRNLEN_CHAR0CMP:%.*]] = icmp ne i8 [[STRNLEN_CHAR0]], 0
47+
; CHECK-NEXT: [[LEN:%.*]] = zext i1 [[STRNLEN_CHAR0CMP]] to i64
48+
; CHECK-NEXT: ret i64 [[LEN]]
4449
;
4550
%ptr = select i1 %C, ptr @s3, ptr @s6
4651

llvm/test/Transforms/SROA/phi-and-select.ll

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -348,13 +348,26 @@ entry:
348348
define i32 @test9_asan(i32 %b, ptr %ptr) sanitize_address {
349349
; Same as @test8 but for a select rather than a PHI node.
350350
;
351-
; CHECK-LABEL: @test9_asan(
352-
; CHECK-NEXT: entry:
353-
; CHECK-NEXT: store i32 0, ptr [[PTR:%.*]], align 4
354-
; CHECK-NEXT: [[TEST:%.*]] = icmp ne i32 [[B:%.*]], 0
355-
; CHECK-NEXT: [[LOADED_SROA_SPECULATE_LOAD_FALSE:%.*]] = load i32, ptr [[PTR]], align 4
356-
; CHECK-NEXT: [[LOADED_SROA_SPECULATED:%.*]] = select i1 [[TEST]], i32 undef, i32 [[LOADED_SROA_SPECULATE_LOAD_FALSE]]
357-
; CHECK-NEXT: ret i32 [[LOADED_SROA_SPECULATED]]
351+
; CHECK-PRESERVE-CFG-LABEL: @test9_asan(
352+
; CHECK-PRESERVE-CFG-NEXT: entry:
353+
; CHECK-PRESERVE-CFG-NEXT: [[F:%.*]] = alloca float, align 4
354+
; CHECK-PRESERVE-CFG-NEXT: store i32 0, ptr [[PTR:%.*]], align 4
355+
; CHECK-PRESERVE-CFG-NEXT: [[TEST:%.*]] = icmp ne i32 [[B:%.*]], 0
356+
; CHECK-PRESERVE-CFG-NEXT: [[SELECT:%.*]] = select i1 [[TEST]], ptr [[F]], ptr [[PTR]]
357+
; CHECK-PRESERVE-CFG-NEXT: [[LOADED:%.*]] = load i32, ptr [[SELECT]], align 4
358+
; CHECK-PRESERVE-CFG-NEXT: ret i32 [[LOADED]]
359+
;
360+
; CHECK-MODIFY-CFG-LABEL: @test9_asan(
361+
; CHECK-MODIFY-CFG-NEXT: entry:
362+
; CHECK-MODIFY-CFG-NEXT: store i32 0, ptr [[PTR:%.*]], align 4
363+
; CHECK-MODIFY-CFG-NEXT: [[TEST:%.*]] = icmp ne i32 [[B:%.*]], 0
364+
; CHECK-MODIFY-CFG-NEXT: [[LOADED_ELSE_VAL:%.*]] = load i32, ptr [[PTR]], align 4
365+
; CHECK-MODIFY-CFG-NEXT: br i1 [[TEST]], label [[ENTRY_THEN:%.*]], label [[ENTRY_CONT:%.*]]
366+
; CHECK-MODIFY-CFG: entry.then:
367+
; CHECK-MODIFY-CFG-NEXT: br label [[ENTRY_CONT]]
368+
; CHECK-MODIFY-CFG: entry.cont:
369+
; CHECK-MODIFY-CFG-NEXT: [[LOADED:%.*]] = phi i32 [ undef, [[ENTRY_THEN]] ], [ [[LOADED_ELSE_VAL]], [[ENTRY:%.*]] ]
370+
; CHECK-MODIFY-CFG-NEXT: ret i32 [[LOADED]]
358371
;
359372
entry:
360373
%f = alloca float

llvm/test/Transforms/SROA/phi-with-duplicate-pred.ll

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,19 +55,20 @@ cleanup7: ; preds = %cleanup
5555
define void @f2_hwasan(i1 %c1) sanitize_hwaddress {
5656
; CHECK-LABEL: @f2_hwasan(
5757
; CHECK-NEXT: entry:
58+
; CHECK-NEXT: [[E:%.*]] = alloca i16, align 1
5859
; CHECK-NEXT: br i1 [[C1:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
5960
; CHECK: if.then:
6061
; CHECK-NEXT: br label [[CLEANUP:%.*]]
6162
; CHECK: cleanup:
62-
; CHECK-NEXT: [[G_0_SROA_SPECULATE_LOAD_CLEANUP:%.*]] = load i16, ptr @a, align 1
6363
; CHECK-NEXT: switch i32 2, label [[CLEANUP7:%.*]] [
6464
; CHECK-NEXT: i32 0, label [[LBL1:%.*]]
6565
; CHECK-NEXT: i32 2, label [[LBL1]]
6666
; CHECK-NEXT: ]
6767
; CHECK: if.else:
6868
; CHECK-NEXT: br label [[LBL1]]
6969
; CHECK: lbl1:
70-
; CHECK-NEXT: [[G_0_SROA_SPECULATED:%.*]] = phi i16 [ [[G_0_SROA_SPECULATE_LOAD_CLEANUP]], [[CLEANUP]] ], [ [[G_0_SROA_SPECULATE_LOAD_CLEANUP]], [[CLEANUP]] ], [ undef, [[IF_ELSE]] ]
70+
; CHECK-NEXT: [[G_0:%.*]] = phi ptr [ @a, [[CLEANUP]] ], [ @a, [[CLEANUP]] ], [ [[E]], [[IF_ELSE]] ]
71+
; CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[G_0]], align 1
7172
; CHECK-NEXT: unreachable
7273
; CHECK: cleanup7:
7374
; CHECK-NEXT: ret void

llvm/test/Transforms/SROA/select-load.ll

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,36 @@ entry:
5959

6060
; Sanitizer will break optimization.
6161
define void @test_multiple_loads_select_asan(i1 %cmp) sanitize_address {
62-
; CHECK-LABEL: @test_multiple_loads_select_asan(
63-
; CHECK-NEXT: entry:
64-
; CHECK-NEXT: [[ADDR_I8_SROA_SPECULATED:%.*]] = select i1 [[CMP:%.*]], ptr undef, ptr undef
65-
; CHECK-NEXT: call void @foo_i8(ptr [[ADDR_I8_SROA_SPECULATED]])
66-
; CHECK-NEXT: [[ADDR_I32_SROA_SPECULATED:%.*]] = select i1 [[CMP]], ptr undef, ptr undef
67-
; CHECK-NEXT: call void @foo_i32(ptr [[ADDR_I32_SROA_SPECULATED]])
68-
; CHECK-NEXT: ret void
62+
; CHECK-PRESERVE-CFG-LABEL: @test_multiple_loads_select_asan(
63+
; CHECK-PRESERVE-CFG-NEXT: entry:
64+
; CHECK-PRESERVE-CFG-NEXT: [[ARGS_SROA_0:%.*]] = alloca ptr, align 8
65+
; CHECK-PRESERVE-CFG-NEXT: [[ARGS_SROA_1:%.*]] = alloca ptr, align 8
66+
; CHECK-PRESERVE-CFG-NEXT: [[SEL_SROA_SEL:%.*]] = select i1 [[CMP:%.*]], ptr [[ARGS_SROA_1]], ptr [[ARGS_SROA_0]]
67+
; CHECK-PRESERVE-CFG-NEXT: [[ADDR_I8:%.*]] = load ptr, ptr [[SEL_SROA_SEL]], align 8
68+
; CHECK-PRESERVE-CFG-NEXT: call void @foo_i8(ptr [[ADDR_I8]])
69+
; CHECK-PRESERVE-CFG-NEXT: [[ADDR_I32:%.*]] = load ptr, ptr [[SEL_SROA_SEL]], align 8
70+
; CHECK-PRESERVE-CFG-NEXT: call void @foo_i32(ptr [[ADDR_I32]])
71+
; CHECK-PRESERVE-CFG-NEXT: ret void
72+
;
73+
; CHECK-MODIFY-CFG-LABEL: @test_multiple_loads_select_asan(
74+
; CHECK-MODIFY-CFG-NEXT: entry:
75+
; CHECK-MODIFY-CFG-NEXT: br i1 [[CMP:%.*]], label [[ENTRY_THEN:%.*]], label [[ENTRY_ELSE:%.*]]
76+
; CHECK-MODIFY-CFG: entry.then:
77+
; CHECK-MODIFY-CFG-NEXT: br label [[ENTRY_CONT:%.*]]
78+
; CHECK-MODIFY-CFG: entry.else:
79+
; CHECK-MODIFY-CFG-NEXT: br label [[ENTRY_CONT]]
80+
; CHECK-MODIFY-CFG: entry.cont:
81+
; CHECK-MODIFY-CFG-NEXT: [[ADDR_I8:%.*]] = phi ptr [ undef, [[ENTRY_THEN]] ], [ undef, [[ENTRY_ELSE]] ]
82+
; CHECK-MODIFY-CFG-NEXT: call void @foo_i8(ptr [[ADDR_I8]])
83+
; CHECK-MODIFY-CFG-NEXT: br i1 [[CMP]], label [[ENTRY_CONT_THEN:%.*]], label [[ENTRY_CONT_ELSE:%.*]]
84+
; CHECK-MODIFY-CFG: entry.cont.then:
85+
; CHECK-MODIFY-CFG-NEXT: br label [[ENTRY_CONT_CONT:%.*]]
86+
; CHECK-MODIFY-CFG: entry.cont.else:
87+
; CHECK-MODIFY-CFG-NEXT: br label [[ENTRY_CONT_CONT]]
88+
; CHECK-MODIFY-CFG: entry.cont.cont:
89+
; CHECK-MODIFY-CFG-NEXT: [[ADDR_I32:%.*]] = phi ptr [ undef, [[ENTRY_CONT_THEN]] ], [ undef, [[ENTRY_CONT_ELSE]] ]
90+
; CHECK-MODIFY-CFG-NEXT: call void @foo_i32(ptr [[ADDR_I32]])
91+
; CHECK-MODIFY-CFG-NEXT: ret void
6992
;
7093
entry:
7194
%args = alloca [2 x %st.args], align 16
@@ -436,13 +459,13 @@ define void @load_of_select_with_noundef_nonnull(ptr %buffer, i1 %b) {
436459
; CHECK-PRESERVE-CFG-LABEL: @load_of_select_with_noundef_nonnull(
437460
; CHECK-PRESERVE-CFG-NEXT: [[UB_PTR:%.*]] = alloca ptr, align 8
438461
; CHECK-PRESERVE-CFG-NEXT: [[SELECT_PTR:%.*]] = select i1 [[B:%.*]], ptr [[BUFFER:%.*]], ptr [[UB_PTR]]
439-
; CHECK-PRESERVE-CFG-NEXT: [[LOAD_PTR:%.*]] = load ptr, ptr [[SELECT_PTR]], align 8, !nonnull !1, !noundef !1
462+
; CHECK-PRESERVE-CFG-NEXT: [[LOAD_PTR:%.*]] = load ptr, ptr [[SELECT_PTR]], align 8, !nonnull [[META1:![0-9]+]], !noundef [[META1]]
440463
; CHECK-PRESERVE-CFG-NEXT: ret void
441464
;
442465
; CHECK-MODIFY-CFG-LABEL: @load_of_select_with_noundef_nonnull(
443466
; CHECK-MODIFY-CFG-NEXT: br i1 [[B:%.*]], label [[DOTTHEN:%.*]], label [[DOTCONT:%.*]]
444467
; CHECK-MODIFY-CFG: .then:
445-
; CHECK-MODIFY-CFG-NEXT: [[LOAD_PTR_THEN_VAL:%.*]] = load ptr, ptr [[BUFFER:%.*]], align 8, !nonnull !2, !noundef !2
468+
; CHECK-MODIFY-CFG-NEXT: [[LOAD_PTR_THEN_VAL:%.*]] = load ptr, ptr [[BUFFER:%.*]], align 8, !nonnull [[META2:![0-9]+]], !noundef [[META2]]
446469
; CHECK-MODIFY-CFG-NEXT: br label [[DOTCONT]]
447470
; CHECK-MODIFY-CFG: .cont:
448471
; CHECK-MODIFY-CFG-NEXT: [[LOAD_PTR:%.*]] = phi ptr [ [[LOAD_PTR_THEN_VAL]], [[DOTTHEN]] ], [ undef, [[TMP0:%.*]] ]

0 commit comments

Comments
 (0)