xref: /llvm-project/llvm/test/CodeGen/X86/stack-guard-oob.ll (revision 2f448bf509432c1a19ec46ab8cbc7353c03c6280)
1; RUN: llc -mtriple=i686 -O0 < %s | FileCheck %s
2; RUN: llc -mtriple=x86_64 -O0 < %s | FileCheck %s
3
4; CHECK-LABEL: in_bounds:
5; CHECK-NOT: __stack_chk_guard
6define i32 @in_bounds() #0 {
7  %var = alloca i32, align 4
8  store i32 0, ptr %var, align 4
9  %ret = load i32, ptr %var, align 4
10  ret i32 %ret
11}
12
13; CHECK-LABEL: constant_out_of_bounds:
14; CHECK: __stack_chk_guard
15define i32 @constant_out_of_bounds() #0 {
16  %var = alloca i32, align 4
17  store i32 0, ptr %var, align 4
18  %gep = getelementptr inbounds i32, ptr %var, i32 1
19  %ret = load i32, ptr %gep, align 4
20  ret i32 %ret
21}
22
23; CHECK-LABEL: nonconstant_out_of_bounds:
24; CHECK: __stack_chk_guard
25define i32 @nonconstant_out_of_bounds(i32 %n) #0 {
26  %var = alloca i32, align 4
27  store i32 0, ptr %var, align 4
28  %gep = getelementptr inbounds i32, ptr %var, i32 %n
29  %ret = load i32, ptr %gep, align 4
30  ret i32 %ret
31}
32
33; CHECK-LABEL: phi_before_gep_in_bounds:
34; CHECK-NOT: __stack_chk_guard
35define i32 @phi_before_gep_in_bounds(i32 %k) #0 {
36entry:
37  %var1 = alloca i32, align 4
38  %var2 = alloca i32, align 4
39  store i32 0, ptr %var1, align 4
40  store i32 0, ptr %var2, align 4
41  %cmp = icmp ne i32 %k, 0
42  br i1 %cmp, label %if, label %then
43
44if:
45  br label %then
46
47then:
48  %ptr = phi ptr [ %var1, %entry ], [ %var2, %if ]
49  %ret = load i32, ptr %ptr, align 4
50  ret i32 %ret
51}
52
53; CHECK-LABEL: phi_before_gep_constant_out_of_bounds:
54; CHECK: __stack_chk_guard
55define i32 @phi_before_gep_constant_out_of_bounds(i32 %k) #0 {
56entry:
57  %var1 = alloca i32, align 4
58  %var2 = alloca i32, align 4
59  store i32 0, ptr %var1, align 4
60  store i32 0, ptr %var2, align 4
61  %cmp = icmp ne i32 %k, 0
62  br i1 %cmp, label %if, label %then
63
64if:
65  br label %then
66
67then:
68  %ptr = phi ptr [ %var1, %entry ], [ %var2, %if ]
69  %gep = getelementptr inbounds i32, ptr %ptr, i32 1
70  %ret = load i32, ptr %gep, align 4
71  ret i32 %ret
72}
73
74; CHECK-LABEL: phi_before_gep_nonconstant_out_of_bounds:
75; CHECK: __stack_chk_guard
76define i32 @phi_before_gep_nonconstant_out_of_bounds(i32 %k, i32 %n) #0 {
77entry:
78  %var1 = alloca i32, align 4
79  %var2 = alloca i32, align 4
80  store i32 0, ptr %var1, align 4
81  store i32 0, ptr %var2, align 4
82  %cmp = icmp ne i32 %k, 0
83  br i1 %cmp, label %if, label %then
84
85if:
86  br label %then
87
88then:
89  %ptr = phi ptr [ %var1, %entry ], [ %var2, %if ]
90  %gep = getelementptr inbounds i32, ptr %ptr, i32 %n
91  %ret = load i32, ptr %gep, align 4
92  ret i32 %ret
93}
94
95; CHECK-LABEL: phi_after_gep_in_bounds:
96; CHECK-NOT: __stack_chk_guard
97define i32 @phi_after_gep_in_bounds(i32 %k) #0 {
98entry:
99  %var1 = alloca i32, align 4
100  %var2 = alloca i32, align 4
101  store i32 0, ptr %var1, align 4
102  store i32 0, ptr %var2, align 4
103  %cmp = icmp ne i32 %k, 0
104  br i1 %cmp, label %if, label %else
105
106if:
107  br label %then
108
109else:
110  br label %then
111
112then:
113  %ptr = phi ptr [ %var1, %if ], [ %var2, %else ]
114  %ret = load i32, ptr %ptr, align 4
115  ret i32 %ret
116}
117
118; CHECK-LABEL: phi_after_gep_constant_out_of_bounds_a:
119; CHECK: __stack_chk_guard
120define i32 @phi_after_gep_constant_out_of_bounds_a(i32 %k) #0 {
121entry:
122  %var1 = alloca i32, align 4
123  %var2 = alloca i32, align 4
124  store i32 0, ptr %var1, align 4
125  store i32 0, ptr %var2, align 4
126  %cmp = icmp ne i32 %k, 0
127  br i1 %cmp, label %if, label %else
128
129if:
130  br label %then
131
132else:
133  %gep2 = getelementptr inbounds i32, ptr %var2, i32 1
134  br label %then
135
136then:
137  %ptr = phi ptr [ %var1, %if ], [ %gep2, %else ]
138  %ret = load i32, ptr %ptr, align 4
139  ret i32 %ret
140}
141
142; CHECK-LABEL: phi_after_gep_constant_out_of_bounds_b:
143; CHECK: __stack_chk_guard
144define i32 @phi_after_gep_constant_out_of_bounds_b(i32 %k) #0 {
145entry:
146  %var1 = alloca i32, align 4
147  %var2 = alloca i32, align 4
148  store i32 0, ptr %var1, align 4
149  store i32 0, ptr %var2, align 4
150  %cmp = icmp ne i32 %k, 0
151  br i1 %cmp, label %if, label %else
152
153if:
154  %gep1 = getelementptr inbounds i32, ptr %var1, i32 1
155  br label %then
156
157else:
158  br label %then
159
160then:
161  %ptr = phi ptr [ %gep1, %if ], [ %var2, %else ]
162  %ret = load i32, ptr %ptr, align 4
163  ret i32 %ret
164}
165
166; CHECK-LABEL: phi_different_types_a:
167; CHECK: __stack_chk_guard
168define i64 @phi_different_types_a(i32 %k) #0 {
169entry:
170  %var1 = alloca i64, align 4
171  %var2 = alloca i32, align 4
172  store i64 0, ptr %var1, align 4
173  store i32 0, ptr %var2, align 4
174  %cmp = icmp ne i32 %k, 0
175  br i1 %cmp, label %if, label %then
176
177if:
178  br label %then
179
180then:
181  %ptr = phi ptr [ %var1, %entry ], [ %var2, %if ]
182  %ret = load i64, ptr %ptr, align 4
183  ret i64 %ret
184}
185
186; CHECK-LABEL: phi_different_types_b:
187; CHECK: __stack_chk_guard
188define i64 @phi_different_types_b(i32 %k) #0 {
189entry:
190  %var1 = alloca i32, align 4
191  %var2 = alloca i64, align 4
192  store i32 0, ptr %var1, align 4
193  store i64 0, ptr %var2, align 4
194  %cmp = icmp ne i32 %k, 0
195  br i1 %cmp, label %if, label %then
196
197if:
198  br label %then
199
200then:
201  %ptr = phi ptr [ %var2, %entry ], [ %var1, %if ]
202  %ret = load i64, ptr %ptr, align 4
203  ret i64 %ret
204}
205
206; CHECK-LABEL: phi_after_gep_nonconstant_out_of_bounds_a:
207; CHECK: __stack_chk_guard
208define i32 @phi_after_gep_nonconstant_out_of_bounds_a(i32 %k, i32 %n) #0 {
209entry:
210  %var1 = alloca i32, align 4
211  %var2 = alloca i32, align 4
212  store i32 0, ptr %var1, align 4
213  store i32 0, ptr %var2, align 4
214  %cmp = icmp ne i32 %k, 0
215  br i1 %cmp, label %if, label %else
216
217if:
218  br label %then
219
220else:
221  %gep2 = getelementptr inbounds i32, ptr %var2, i32 %n
222  br label %then
223
224then:
225  %ptr = phi ptr [ %var1, %if ], [ %gep2, %else ]
226  %ret = load i32, ptr %ptr, align 4
227  ret i32 %ret
228}
229
230; CHECK-LABEL: phi_after_gep_nonconstant_out_of_bounds_b:
231; CHECK: __stack_chk_guard
232define i32 @phi_after_gep_nonconstant_out_of_bounds_b(i32 %k, i32 %n) #0 {
233entry:
234  %var1 = alloca i32, align 4
235  %var2 = alloca i32, align 4
236  store i32 0, ptr %var1, align 4
237  store i32 0, ptr %var2, align 4
238  %cmp = icmp ne i32 %k, 0
239  br i1 %cmp, label %if, label %else
240
241if:
242  %gep1 = getelementptr inbounds i32, ptr %var1, i32 %n
243  br label %then
244
245else:
246  br label %then
247
248then:
249  %ptr = phi ptr [ %gep1, %if ], [ %var2, %else ]
250  %ret = load i32, ptr %ptr, align 4
251  ret i32 %ret
252}
253
254%struct.outer = type { %struct.inner, %struct.inner }
255%struct.inner = type { i32, i32 }
256
257; CHECK-LABEL: struct_in_bounds:
258; CHECK-NOT: __stack_chk_guard
259define void @struct_in_bounds() #0 {
260  %var = alloca %struct.outer, align 4
261  %outergep = getelementptr inbounds %struct.outer, ptr %var, i32 0, i32 1
262  %innergep = getelementptr inbounds %struct.inner, ptr %outergep, i32 0, i32 1
263  store i32 0, ptr %innergep, align 4
264  ret void
265}
266
267; CHECK-LABEL: struct_constant_out_of_bounds_a:
268; CHECK: __stack_chk_guard
269define void @struct_constant_out_of_bounds_a() #0 {
270  %var = alloca %struct.outer, align 4
271  %outergep = getelementptr inbounds %struct.outer, ptr %var, i32 1, i32 0
272  store i32 0, ptr %outergep, align 4
273  ret void
274}
275
276; CHECK-LABEL: struct_constant_out_of_bounds_b:
277; Here the offset is out-of-bounds of the addressed struct.inner member, but
278; still within bounds of the outer struct so no stack guard is needed.
279; CHECK-NOT: __stack_chk_guard
280define void @struct_constant_out_of_bounds_b() #0 {
281  %var = alloca %struct.outer, align 4
282  %innergep = getelementptr inbounds %struct.inner, ptr %var, i32 1, i32 0
283  store i32 0, ptr %innergep, align 4
284  ret void
285}
286
287; CHECK-LABEL: struct_constant_out_of_bounds_c:
288; Here we are out-of-bounds of both the inner and outer struct.
289; CHECK: __stack_chk_guard
290define void @struct_constant_out_of_bounds_c() #0 {
291  %var = alloca %struct.outer, align 4
292  %outergep = getelementptr inbounds %struct.outer, ptr %var, i32 0, i32 1
293  %innergep = getelementptr inbounds %struct.inner, ptr %outergep, i32 1, i32 0
294  store i32 0, ptr %innergep, align 4
295  ret void
296}
297
298; CHECK-LABEL: struct_nonconstant_out_of_bounds_a:
299; CHECK: __stack_chk_guard
300define void @struct_nonconstant_out_of_bounds_a(i32 %n) #0 {
301  %var = alloca %struct.outer, align 4
302  %outergep = getelementptr inbounds %struct.outer, ptr %var, i32 %n, i32 0
303  store i32 0, ptr %outergep, align 4
304  ret void
305}
306
307; CHECK-LABEL: struct_nonconstant_out_of_bounds_b:
308; CHECK: __stack_chk_guard
309define void @struct_nonconstant_out_of_bounds_b(i32 %n) #0 {
310  %var = alloca %struct.outer, align 4
311  %innergep = getelementptr inbounds %struct.inner, ptr %var, i32 %n, i32 0
312  store i32 0, ptr %innergep, align 4
313  ret void
314}
315
316; CHECK-LABEL: bitcast_smaller_load
317; CHECK-NOT: __stack_chk_guard
318define i32 @bitcast_smaller_load() #0 {
319  %var = alloca i64, align 4
320  store i64 0, ptr %var, align 4
321  %ret = load i32, ptr %var, align 4
322  ret i32 %ret
323}
324
325; CHECK-LABEL: bitcast_same_size_load
326; CHECK-NOT: __stack_chk_guard
327define i32 @bitcast_same_size_load() #0 {
328  %var = alloca i64, align 4
329  store i64 0, ptr %var, align 4
330  %gep = getelementptr inbounds %struct.inner, ptr %var, i32 0, i32 1
331  %ret = load i32, ptr %gep, align 4
332  ret i32 %ret
333}
334
335; CHECK-LABEL: bitcast_larger_load
336; CHECK: __stack_chk_guard
337define i64 @bitcast_larger_load() #0 {
338  %var = alloca i32, align 4
339  store i32 0, ptr %var, align 4
340  %ret = load i64, ptr %var, align 4
341  ret i64 %ret
342}
343
344; CHECK-LABEL: bitcast_larger_store
345; CHECK: __stack_chk_guard
346define i32 @bitcast_larger_store() #0 {
347  %var = alloca i32, align 4
348  store i64 0, ptr %var, align 4
349  %ret = load i32, ptr %var, align 4
350  ret i32 %ret
351}
352
353; CHECK-LABEL: bitcast_larger_cmpxchg
354; CHECK: __stack_chk_guard
355define i64 @bitcast_larger_cmpxchg(i64 %desired, i64 %new) #0 {
356  %var = alloca i32, align 4
357  %pair = cmpxchg ptr %var, i64 %desired, i64 %new seq_cst monotonic
358  %ret = extractvalue { i64, i1 } %pair, 0
359  ret i64 %ret
360}
361
362; CHECK-LABEL: bitcast_larger_atomic_rmw
363; CHECK: __stack_chk_guard
364define i64 @bitcast_larger_atomic_rmw() #0 {
365  %var = alloca i32, align 4
366  %ret = atomicrmw add ptr %var, i64 1 monotonic
367  ret i64 %ret
368}
369
370%struct.packed = type <{ i16, i32 }>
371
372; CHECK-LABEL: bitcast_overlap
373; CHECK: __stack_chk_guard
374define i32 @bitcast_overlap() #0 {
375  %var = alloca i32, align 4
376  %gep = getelementptr inbounds %struct.packed, ptr %var, i32 0, i32 1
377  %ret = load i32, ptr %gep, align 2
378  ret i32 %ret
379}
380
381%struct.multi_dimensional = type { [10 x [10 x i32]], i32 }
382
383; CHECK-LABEL: multi_dimensional_array
384; CHECK: __stack_chk_guard
385define i32 @multi_dimensional_array() #0 {
386  %var = alloca %struct.multi_dimensional, align 4
387  %gep2 = getelementptr inbounds [10 x [10 x i32]], ptr %var, i32 0, i32 10
388  %gep3 = getelementptr inbounds [10 x i32], ptr %gep2, i32 0, i32 5
389  %ret = load i32, ptr %gep3, align 4
390  ret i32 %ret
391}
392
393attributes #0 = { sspstrong }
394