1; RUN: opt -S -analyze -stack-safety-local < %s | FileCheck %s --check-prefixes=CHECK,LOCAL 2; RUN: opt -S -passes="print<stack-safety-local>" -disable-output < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,LOCAL 3; RUN: opt -S -analyze -stack-safety < %s | FileCheck %s --check-prefixes=CHECK,GLOBAL 4; RUN: opt -S -passes="print-stack-safety" -disable-output < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,GLOBAL 5 6target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 7target triple = "x86_64-unknown-linux-gnu" 8 9@sink = global i8* null, align 8 10 11declare void @llvm.memset.p0i8.i32(i8* %dest, i8 %val, i32 %len, i1 %isvolatile) 12declare void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 %isvolatile) 13declare void @llvm.memmove.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 %isvolatile) 14 15; Address leaked. 16define void @LeakAddress() { 17; CHECK-LABEL: @LeakAddress dso_preemptable{{$}} 18; CHECK-NEXT: args uses: 19; CHECK-NEXT: allocas uses: 20; CHECK-NEXT: x[4]: full-set{{$}} 21; CHECK-NOT: ]: 22entry: 23 %x = alloca i32, align 4 24 %x1 = bitcast i32* %x to i8* 25 store i8* %x1, i8** @sink, align 8 26 ret void 27} 28 29define void @StoreInBounds() { 30; CHECK-LABEL: @StoreInBounds dso_preemptable{{$}} 31; CHECK-NEXT: args uses: 32; CHECK-NEXT: allocas uses: 33; CHECK-NEXT: x[4]: [0,1){{$}} 34; CHECK-NOT: ]: 35entry: 36 %x = alloca i32, align 4 37 %x1 = bitcast i32* %x to i8* 38 store i8 0, i8* %x1, align 1 39 ret void 40} 41 42define void @StoreInBounds2() { 43; CHECK-LABEL: @StoreInBounds2 dso_preemptable{{$}} 44; CHECK-NEXT: args uses: 45; CHECK-NEXT: allocas uses: 46; CHECK-NEXT: x[4]: [0,4){{$}} 47; CHECK-NOT: ]: 48entry: 49 %x = alloca i32, align 4 50 store i32 0, i32* %x, align 4 51 ret void 52} 53 54define void @StoreInBounds3() { 55; CHECK-LABEL: @StoreInBounds3 dso_preemptable{{$}} 56; CHECK-NEXT: args uses: 57; CHECK-NEXT: allocas uses: 58; CHECK-NEXT: x[4]: [2,3){{$}} 59; CHECK-NOT: ]: 60entry: 61 %x = alloca i32, align 4 62 %x1 = bitcast i32* %x to i8* 63 %x2 = getelementptr i8, i8* %x1, i64 2 64 store i8 0, i8* %x2, align 1 65 ret void 66} 67 68; FIXME: ScalarEvolution does not look through ptrtoint/inttoptr. 69define void @StoreInBounds4() { 70; CHECK-LABEL: @StoreInBounds4 dso_preemptable{{$}} 71; CHECK-NEXT: args uses: 72; CHECK-NEXT: allocas uses: 73; CHECK-NEXT: x[4]: [2,-1){{$}} 74; CHECK-NOT: ]: 75entry: 76 %x = alloca i32, align 4 77 %x1 = ptrtoint i32* %x to i64 78 %x2 = add i64 %x1, 2 79 %x3 = inttoptr i64 %x2 to i8* 80 store i8 0, i8* %x3, align 1 81 ret void 82} 83 84define void @StoreOutOfBounds() { 85; CHECK-LABEL: @StoreOutOfBounds dso_preemptable{{$}} 86; CHECK-NEXT: args uses: 87; CHECK-NEXT: allocas uses: 88; CHECK-NEXT: x[4]: [2,6){{$}} 89; CHECK-NOT: ]: 90entry: 91 %x = alloca i32, align 4 92 %x1 = bitcast i32* %x to i8* 93 %x2 = getelementptr i8, i8* %x1, i64 2 94 %x3 = bitcast i8* %x2 to i32* 95 store i32 0, i32* %x3, align 1 96 ret void 97} 98 99; There is no difference in load vs store handling. 100define void @LoadInBounds() { 101; CHECK-LABEL: @LoadInBounds dso_preemptable{{$}} 102; CHECK-NEXT: args uses: 103; CHECK-NEXT: allocas uses: 104; CHECK-NEXT: x[4]: [0,1){{$}} 105; CHECK-NOT: ]: 106entry: 107 %x = alloca i32, align 4 108 %x1 = bitcast i32* %x to i8* 109 %v = load i8, i8* %x1, align 1 110 ret void 111} 112 113define void @LoadOutOfBounds() { 114; CHECK-LABEL: @LoadOutOfBounds dso_preemptable{{$}} 115; CHECK-NEXT: args uses: 116; CHECK-NEXT: allocas uses: 117; CHECK-NEXT: x[4]: [2,6){{$}} 118; CHECK-NOT: ]: 119entry: 120 %x = alloca i32, align 4 121 %x1 = bitcast i32* %x to i8* 122 %x2 = getelementptr i8, i8* %x1, i64 2 123 %x3 = bitcast i8* %x2 to i32* 124 %v = load i32, i32* %x3, align 1 125 ret void 126} 127 128; Leak through ret. 129define i8* @Ret() { 130; CHECK-LABEL: @Ret dso_preemptable{{$}} 131; CHECK-NEXT: args uses: 132; CHECK-NEXT: allocas uses: 133; CHECK-NEXT: x[4]: full-set{{$}} 134; CHECK-NOT: ]: 135entry: 136 %x = alloca i32, align 4 137 %x1 = bitcast i32* %x to i8* 138 %x2 = getelementptr i8, i8* %x1, i64 2 139 ret i8* %x2 140} 141 142declare void @Foo(i16* %p) 143 144define void @DirectCall() { 145; CHECK-LABEL: @DirectCall dso_preemptable{{$}} 146; CHECK-NEXT: args uses: 147; CHECK-NEXT: allocas uses: 148; LOCAL-NEXT: x[8]: empty-set, @Foo(arg0, [2,3)){{$}} 149; GLOBAL-NEXT: x[8]: full-set, @Foo(arg0, [2,3)){{$}} 150; CHECK-NOT: ]: 151entry: 152 %x = alloca i64, align 4 153 %x1 = bitcast i64* %x to i16* 154 %x2 = getelementptr i16, i16* %x1, i64 1 155 call void @Foo(i16* %x2); 156 ret void 157} 158 159; Indirect calls can not be analyzed (yet). 160; FIXME: %p[]: full-set looks invalid 161define void @IndirectCall(void (i8*)* %p) { 162; CHECK-LABEL: @IndirectCall dso_preemptable{{$}} 163; CHECK-NEXT: args uses: 164; CHECK-NEXT: p[]: full-set{{$}} 165; CHECK-NEXT: allocas uses: 166; CHECK-NEXT: x[4]: full-set{{$}} 167; CHECK-NOT: ]: 168entry: 169 %x = alloca i32, align 4 170 %x1 = bitcast i32* %x to i8* 171 call void %p(i8* %x1); 172 ret void 173} 174 175define void @NonConstantOffset(i1 zeroext %z) { 176; CHECK-LABEL: @NonConstantOffset dso_preemptable{{$}} 177; CHECK-NEXT: args uses: 178; CHECK-NEXT: z[]: full-set{{$}} 179; CHECK-NEXT: allocas uses: 180; CHECK-NEXT: x[4]: [0,4){{$}} 181; CHECK-NOT: ]: 182entry: 183 %x = alloca i32, align 4 184 %x1 = bitcast i32* %x to i8* 185 %idx = select i1 %z, i64 1, i64 2 186 %x2 = getelementptr i8, i8* %x1, i64 %idx 187 store i8 0, i8* %x2, align 1 188 ret void 189} 190 191define void @NonConstantOffsetOOB(i1 zeroext %z) { 192; CHECK-LABEL: @NonConstantOffsetOOB dso_preemptable{{$}} 193; CHECK-NEXT: args uses: 194; CHECK-NEXT: z[]: full-set{{$}} 195; CHECK-NEXT: allocas uses: 196; CHECK-NEXT: x[4]: [0,6){{$}} 197; CHECK-NOT: ]: 198entry: 199 %x = alloca i32, align 4 200 %x1 = bitcast i32* %x to i8* 201 %idx = select i1 %z, i64 1, i64 4 202 %x2 = getelementptr i8, i8* %x1, i64 %idx 203 store i8 0, i8* %x2, align 1 204 ret void 205} 206 207define void @ArrayAlloca() { 208; CHECK-LABEL: @ArrayAlloca dso_preemptable{{$}} 209; CHECK-NEXT: args uses: 210; CHECK-NEXT: allocas uses: 211; CHECK-NEXT: x[40]: [36,40){{$}} 212; CHECK-NOT: ]: 213entry: 214 %x = alloca i32, i32 10, align 4 215 %x1 = bitcast i32* %x to i8* 216 %x2 = getelementptr i8, i8* %x1, i64 36 217 %x3 = bitcast i8* %x2 to i32* 218 store i32 0, i32* %x3, align 1 219 ret void 220} 221 222define void @ArrayAllocaOOB() { 223; CHECK-LABEL: @ArrayAllocaOOB dso_preemptable{{$}} 224; CHECK-NEXT: args uses: 225; CHECK-NEXT: allocas uses: 226; CHECK-NEXT: x[40]: [37,41){{$}} 227; CHECK-NOT: ]: 228entry: 229 %x = alloca i32, i32 10, align 4 230 %x1 = bitcast i32* %x to i8* 231 %x2 = getelementptr i8, i8* %x1, i64 37 232 %x3 = bitcast i8* %x2 to i32* 233 store i32 0, i32* %x3, align 1 234 ret void 235} 236 237define void @DynamicAllocaUnused(i64 %size) { 238; CHECK-LABEL: @DynamicAllocaUnused dso_preemptable{{$}} 239; CHECK-NEXT: args uses: 240; CHECK-NEXT: size[]: empty-set{{$}} 241; CHECK-NEXT: allocas uses: 242; CHECK-NEXT: x[0]: empty-set{{$}} 243; CHECK-NOT: ]: 244entry: 245 %x = alloca i32, i64 %size, align 16 246 ret void 247} 248 249; Dynamic alloca with unknown size. 250define void @DynamicAlloca(i64 %size) { 251; CHECK-LABEL: @DynamicAlloca dso_preemptable{{$}} 252; CHECK-NEXT: args uses: 253; CHECK-NEXT: size[]: [0,-12){{$}} 254; CHECK-NEXT: allocas uses: 255; CHECK-NEXT: x[0]: [0,4){{$}} 256; CHECK-NOT: ]: 257entry: 258 %x = alloca i32, i64 %size, align 16 259 store i32 0, i32* %x, align 1 260 ret void 261} 262 263; Dynamic alloca with limited size. 264; FIXME: could be proved safe. Implement. 265define void @DynamicAllocaFiniteSizeRange(i1 zeroext %z) { 266; CHECK-LABEL: @DynamicAllocaFiniteSizeRange dso_preemptable{{$}} 267; CHECK-NEXT: args uses: 268; CHECK-NEXT: z[]: [0,-12){{$}} 269; CHECK-NEXT: allocas uses: 270; CHECK-NEXT: x[0]: [0,4){{$}} 271; CHECK-NOT: ]: 272entry: 273 %size = select i1 %z, i64 3, i64 5 274 %x = alloca i32, i64 %size, align 16 275 store i32 0, i32* %x, align 1 276 ret void 277} 278 279define signext i8 @SimpleLoop() { 280; CHECK-LABEL: @SimpleLoop dso_preemptable{{$}} 281; CHECK-NEXT: args uses: 282; CHECK-NEXT: allocas uses: 283; CHECK-NEXT: x[10]: [0,10){{$}} 284; CHECK-NOT: ]: 285entry: 286 %x = alloca [10 x i8], align 1 287 %0 = getelementptr inbounds [10 x i8], [10 x i8]* %x, i64 0, i64 0 288 %lftr.limit = getelementptr inbounds [10 x i8], [10 x i8]* %x, i64 0, i64 10 289 br label %for.body 290 291for.body: 292 %sum.010 = phi i8 [ 0, %entry ], [ %add, %for.body ] 293 %p.09 = phi i8* [ %0, %entry ], [ %incdec.ptr, %for.body ] 294 %incdec.ptr = getelementptr inbounds i8, i8* %p.09, i64 1 295 %1 = load volatile i8, i8* %p.09, align 1 296 %add = add i8 %1, %sum.010 297 %exitcond = icmp eq i8* %incdec.ptr, %lftr.limit 298 br i1 %exitcond, label %for.cond.cleanup, label %for.body 299 300for.cond.cleanup: 301 ret i8 %add 302} 303 304; OOB in a loop. 305define signext i8 @SimpleLoopOOB() { 306; CHECK-LABEL: @SimpleLoopOOB dso_preemptable{{$}} 307; CHECK-NEXT: args uses: 308; CHECK-NEXT: allocas uses: 309; CHECK-NEXT: x[10]: [0,11){{$}} 310; CHECK-NOT: ]: 311entry: 312 %x = alloca [10 x i8], align 1 313 %0 = getelementptr inbounds [10 x i8], [10 x i8]* %x, i64 0, i64 0 314 ; 11 iterations 315 %lftr.limit = getelementptr inbounds [10 x i8], [10 x i8]* %x, i64 0, i64 11 316 br label %for.body 317 318for.body: 319 %sum.010 = phi i8 [ 0, %entry ], [ %add, %for.body ] 320 %p.09 = phi i8* [ %0, %entry ], [ %incdec.ptr, %for.body ] 321 %incdec.ptr = getelementptr inbounds i8, i8* %p.09, i64 1 322 %1 = load volatile i8, i8* %p.09, align 1 323 %add = add i8 %1, %sum.010 324 %exitcond = icmp eq i8* %incdec.ptr, %lftr.limit 325 br i1 %exitcond, label %for.cond.cleanup, label %for.body 326 327for.cond.cleanup: 328 ret i8 %add 329} 330 331; FIXME: we don't understand that %sz in the memset call is limited to 128 by the preceding check. 332define dso_local void @SizeCheck(i32 %sz) { 333; CHECK-LABEL: @SizeCheck{{$}} 334; CHECK-NEXT: args uses: 335; CHECK-NEXT: sz[]: [0,1){{$}} 336; CHECK-NEXT: allocas uses: 337; CHECK-NEXT: x1[128]: full-set{{$}} 338; CHECK-NOT: ]: 339entry: 340 %x1 = alloca [128 x i8], align 16 341 %x1.sub = getelementptr inbounds [128 x i8], [128 x i8]* %x1, i64 0, i64 0 342 %cmp = icmp slt i32 %sz, 129 343 br i1 %cmp, label %if.then, label %if.end 344 345if.then: 346 call void @llvm.memset.p0i8.i32(i8* nonnull align 16 %x1.sub, i8 0, i32 %sz, i1 false) 347 br label %if.end 348 349if.end: 350 ret void 351} 352 353; FIXME: scalable allocas are considered to be of size zero, and scalable accesses to be full-range. 354; This effectively disables safety analysis for scalable allocations. 355define void @Scalable(<vscale x 4 x i32>* %p, <vscale x 4 x i32>* %unused, <vscale x 4 x i32> %v) { 356; CHECK-LABEL: @Scalable dso_preemptable{{$}} 357; CHECK-NEXT: args uses: 358; CHECK-NEXT: p[]: full-set 359; CHECK-NEXT: unused[]: empty-set 360; CHECK-NEXT: v[]: full-set 361; CHECK-NEXT: allocas uses: 362; CHECK-NEXT: x[0]: [0,1){{$}} 363; CHECK-NOT: ]: 364entry: 365 %x = alloca <vscale x 4 x i32>, align 4 366 %x1 = bitcast <vscale x 4 x i32>* %x to i8* 367 store i8 0, i8* %x1, align 1 368 store <vscale x 4 x i32> %v, <vscale x 4 x i32>* %p, align 4 369 ret void 370} 371 372%zerosize_type = type {} 373 374define void @ZeroSize(%zerosize_type *%p) { 375; CHECK-LABEL: @ZeroSize dso_preemptable{{$}} 376; CHECK-NEXT: args uses: 377; CHECK-NEXT: p[]: empty-set 378; CHECK-NEXT: allocas uses: 379; CHECK-NEXT: x[0]: empty-set 380; CHECK-NOT: ]: 381entry: 382 %x = alloca %zerosize_type, align 4 383 store %zerosize_type undef, %zerosize_type* %x, align 4 384 store %zerosize_type undef, %zerosize_type* undef, align 4 385 %val = load %zerosize_type, %zerosize_type* %p, align 4 386 ret void 387} 388