blob: 821bfc86a0e5b28667362d949b952543320897c8 [file] [log] [blame]
Arthur Eubanks7c2f2762020-07-17 17:49:46 -07001; RUN: opt < %s -asan -asan-module -enable-new-pm=0 -asan-use-after-return -S | FileCheck %s
2; RUN: opt < %s -passes='asan-pipeline' -asan-use-after-return -S | FileCheck %s
Vedant Kumar5f185a82020-03-31 15:27:06 -07003
4; Source (-O0 -fsanitize=address -fsanitize-address-use-after-scope):
5;; struct S { int x, y; };
6;; void swap(S *a, S *b, bool doit) {
7;; if (!doit)
8;; return;
9;; auto tmp = *a;
10;; *a = *b;
11;; *b = tmp;
12;; }
13
14target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
15target triple = "x86_64-apple-macosx10.14.0"
16
17%struct.S = type { i32, i32 }
18
19; CHECK-LABEL: define {{.*}} @_Z4swapP1SS0_b(
20
21; First come the argument allocas.
22; CHECK: [[argA:%.*]] = alloca %struct.S*,
23; CHECK-NEXT: [[argB:%.*]] = alloca %struct.S*,
24; CHECK-NEXT: [[argDoit:%.*]] = alloca i8,
25
26; Next, the stores into the argument allocas.
27; CHECK-NEXT: store %struct.S* {{.*}}, %struct.S** [[argA]]
28; CHECK-NEXT: store %struct.S* {{.*}}, %struct.S** [[argB]]
29; CHECK-NEXT: [[frombool:%.*]] = zext i1 {{.*}} to i8
30; CHECK-NEXT: store i8 [[frombool]], i8* [[argDoit]]
31
32define void @_Z4swapP1SS0_b(%struct.S* %a, %struct.S* %b, i1 zeroext %doit) sanitize_address {
33entry:
34 %a.addr = alloca %struct.S*, align 8
35 %b.addr = alloca %struct.S*, align 8
36 %doit.addr = alloca i8, align 1
37 %tmp = alloca %struct.S, align 4
38 store %struct.S* %a, %struct.S** %a.addr, align 8
39 store %struct.S* %b, %struct.S** %b.addr, align 8
40 %frombool = zext i1 %doit to i8
41 store i8 %frombool, i8* %doit.addr, align 1
42 %0 = load i8, i8* %doit.addr, align 1
43 %tobool = trunc i8 %0 to i1
44 br i1 %tobool, label %if.end, label %if.then
45
46if.then: ; preds = %entry
47 br label %return
48
49if.end: ; preds = %entry
50 %1 = load %struct.S*, %struct.S** %a.addr, align 8
51 %2 = bitcast %struct.S* %tmp to i8*
52 %3 = bitcast %struct.S* %1 to i8*
53 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %2, i8* align 4 %3, i64 8, i1 false)
54 %4 = load %struct.S*, %struct.S** %b.addr, align 8
55 %5 = load %struct.S*, %struct.S** %a.addr, align 8
56 %6 = bitcast %struct.S* %5 to i8*
57 %7 = bitcast %struct.S* %4 to i8*
58 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %6, i8* align 4 %7, i64 8, i1 false)
59 %8 = load %struct.S*, %struct.S** %b.addr, align 8
60 %9 = bitcast %struct.S* %8 to i8*
61 %10 = bitcast %struct.S* %tmp to i8*
62 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %9, i8* align 4 %10, i64 8, i1 false)
63 br label %return
64
65return: ; preds = %if.end, %if.then
66 ret void
67}
68
69; Synthetic test case, meant to check that we do not reorder instructions past
70; a load when attempting to hoist argument init insts.
71; CHECK-LABEL: define {{.*}} @func_with_load_in_arginit_sequence
72; CHECK: [[argA:%.*]] = alloca %struct.S*,
73; CHECK-NEXT: [[argB:%.*]] = alloca %struct.S*,
74; CHECK-NEXT: [[argDoit:%.*]] = alloca i8,
75; CHECK-NEXT: store %struct.S* {{.*}}, %struct.S** [[argA]]
76; CHECK-NEXT: store %struct.S* {{.*}}, %struct.S** [[argB]]
77; CHECK-NEXT: [[stack_base:%.*]] = alloca i64
78define void @func_with_load_in_arginit_sequence(%struct.S* %a, %struct.S* %b, i1 zeroext %doit) sanitize_address {
79entry:
80 %a.addr = alloca %struct.S*, align 8
81 %b.addr = alloca %struct.S*, align 8
82 %doit.addr = alloca i8, align 1
83 %tmp = alloca %struct.S, align 4
84 store %struct.S* %a, %struct.S** %a.addr, align 8
85 store %struct.S* %b, %struct.S** %b.addr, align 8
86
87 ; This load prevents the next argument init sequence from being moved.
88 %0 = load i8, i8* %doit.addr, align 1
89
90 %frombool = zext i1 %doit to i8
91 store i8 %frombool, i8* %doit.addr, align 1
92 %tobool = trunc i8 %0 to i1
93 br i1 %tobool, label %if.end, label %if.then
94
95if.then: ; preds = %entry
96 br label %return
97
98if.end: ; preds = %entry
99 %1 = load %struct.S*, %struct.S** %a.addr, align 8
100 %2 = bitcast %struct.S* %tmp to i8*
101 %3 = bitcast %struct.S* %1 to i8*
102 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %2, i8* align 4 %3, i64 8, i1 false)
103 %4 = load %struct.S*, %struct.S** %b.addr, align 8
104 %5 = load %struct.S*, %struct.S** %a.addr, align 8
105 %6 = bitcast %struct.S* %5 to i8*
106 %7 = bitcast %struct.S* %4 to i8*
107 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %6, i8* align 4 %7, i64 8, i1 false)
108 %8 = load %struct.S*, %struct.S** %b.addr, align 8
109 %9 = bitcast %struct.S* %8 to i8*
110 %10 = bitcast %struct.S* %tmp to i8*
111 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %9, i8* align 4 %10, i64 8, i1 false)
112 br label %return
113
114return: ; preds = %if.end, %if.then
115 ret void
116}
117
118; Synthetic test case, meant to check that we can handle functions with more
119; than one interesting alloca.
120; CHECK-LABEL: define {{.*}} @func_with_multiple_interesting_allocas
121; CHECK: [[argA:%.*]] = alloca %struct.S*,
122; CHECK-NEXT: [[argB:%.*]] = alloca %struct.S*,
123; CHECK-NEXT: [[argDoit:%.*]] = alloca i8,
124; CHECK-NEXT: store %struct.S* {{.*}}, %struct.S** [[argA]]
125; CHECK-NEXT: store %struct.S* {{.*}}, %struct.S** [[argB]]
126; CHECK-NEXT: [[frombool:%.*]] = zext i1 {{.*}} to i8
127; CHECK-NEXT: store i8 [[frombool]], i8* [[argDoit]]
128define void @func_with_multiple_interesting_allocas(%struct.S* %a, %struct.S* %b, i1 zeroext %doit) sanitize_address {
129entry:
130 %a.addr = alloca %struct.S*, align 8
131 %b.addr = alloca %struct.S*, align 8
132 %doit.addr = alloca i8, align 1
133 %tmp = alloca %struct.S, align 4
134 %tmp2 = alloca %struct.S, align 4
135 store %struct.S* %a, %struct.S** %a.addr, align 8
136 store %struct.S* %b, %struct.S** %b.addr, align 8
137 %frombool = zext i1 %doit to i8
138 store i8 %frombool, i8* %doit.addr, align 1
139 %0 = load i8, i8* %doit.addr, align 1
140 %tobool = trunc i8 %0 to i1
141 br i1 %tobool, label %if.end, label %if.then
142
143if.then: ; preds = %entry
144 br label %return
145
146if.end: ; preds = %entry
147 %1 = load %struct.S*, %struct.S** %a.addr, align 8
148 %2 = bitcast %struct.S* %tmp to i8*
149 %3 = bitcast %struct.S* %1 to i8*
150 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %2, i8* align 4 %3, i64 8, i1 false)
151 %4 = load %struct.S*, %struct.S** %b.addr, align 8
152 %5 = bitcast %struct.S* %tmp2 to i8*
153 %6 = bitcast %struct.S* %4 to i8*
154 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %5, i8* align 4 %6, i64 8, i1 false)
155 %7 = load %struct.S*, %struct.S** %b.addr, align 8
156 %8 = load %struct.S*, %struct.S** %a.addr, align 8
157 %9 = bitcast %struct.S* %8 to i8*
158 %10 = bitcast %struct.S* %7 to i8*
159 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %9, i8* align 4 %10, i64 8, i1 false)
160 %11 = load %struct.S*, %struct.S** %b.addr, align 8
161 %12 = bitcast %struct.S* %11 to i8*
162 %13 = bitcast %struct.S* %tmp to i8*
163 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %12, i8* align 4 %13, i64 8, i1 false)
164 %14 = load %struct.S*, %struct.S** %a.addr, align 8
165 %15 = bitcast %struct.S* %14 to i8*
166 %16 = bitcast %struct.S* %tmp2 to i8*
167 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %15, i8* align 4 %16, i64 8, i1 false)
168 br label %return
169
170return: ; preds = %if.end, %if.then
171 ret void
172}
173
174declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg)