1; RUN: opt < %s -stack-tagging -S -o - | FileCheck %s --check-prefixes=CHECK,SSI 2; RUN: opt < %s -stack-tagging -stack-tagging-use-stack-safety=0 -S -o - | FileCheck %s --check-prefixes=CHECK,NOSSI 3 4target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" 5target triple = "aarch64--linux-android" 6 7declare void @use8(i8*) 8declare void @use32(i32*) 9declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) 10declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) 11 12define dso_local void @noUse32(i32*) sanitize_memtag { 13entry: 14 ret void 15} 16 17define void @OneVar() sanitize_memtag { 18entry: 19 %x = alloca i32, align 4 20 call void @use32(i32* %x) 21 ret void 22} 23 24; CHECK-LABEL: define void @OneVar( 25; CHECK: [[BASE:%.*]] = call i8* @llvm.aarch64.irg.sp(i64 0) 26; CHECK: [[X:%.*]] = alloca { i32, [12 x i8] }, align 16 27; CHECK: [[TX:%.*]] = call { i32, [12 x i8] }* @llvm.aarch64.tagp.{{.*}}({ i32, [12 x i8] }* [[X]], i8* [[BASE]], i64 0) 28; CHECK: [[TX8:%.*]] = bitcast { i32, [12 x i8] }* [[TX]] to i8* 29; CHECK: call void @llvm.aarch64.settag(i8* [[TX8]], i64 16) 30; CHECK: [[GEP32:%.*]] = bitcast { i32, [12 x i8] }* [[TX]] to i32* 31; CHECK: call void @use32(i32* [[GEP32]]) 32; CHECK: [[GEP8:%.*]] = bitcast { i32, [12 x i8] }* [[X]] to i8* 33; CHECK: call void @llvm.aarch64.settag(i8* [[GEP8]], i64 16) 34; CHECK: ret void 35 36 37define void @ManyVars() sanitize_memtag { 38entry: 39 %x1 = alloca i32, align 4 40 %x2 = alloca i8, align 4 41 %x3 = alloca i32, i32 11, align 4 42 %x4 = alloca i32, align 4 43 call void @use32(i32* %x1) 44 call void @use8(i8* %x2) 45 call void @use32(i32* %x3) 46 ret void 47} 48 49; CHECK-LABEL: define void @ManyVars( 50; CHECK: alloca { i32, [12 x i8] }, align 16 51; CHECK: call { i32, [12 x i8] }* @llvm.aarch64.tagp.{{.*}}({ i32, [12 x i8] }* {{.*}}, i64 0) 52; CHECK: call void @llvm.aarch64.settag(i8* {{.*}}, i64 16) 53; CHECK: alloca { i8, [15 x i8] }, align 16 54; CHECK: call { i8, [15 x i8] }* @llvm.aarch64.tagp.{{.*}}({ i8, [15 x i8] }* {{.*}}, i64 1) 55; CHECK: call void @llvm.aarch64.settag(i8* {{.*}}, i64 16) 56; CHECK: alloca { [11 x i32], [4 x i8] }, align 16 57; CHECK: call { [11 x i32], [4 x i8] }* @llvm.aarch64.tagp.{{.*}}({ [11 x i32], [4 x i8] }* {{.*}}, i64 2) 58; CHECK: call void @llvm.aarch64.settag(i8* {{.*}}, i64 48) 59; SSI: alloca i32, align 4 60; NOSSI: alloca { i32, [12 x i8] }, align 16 61; NOSSI: @llvm.aarch64.tagp. 62; NOSSI: call void @llvm.aarch64.settag(i8* {{.*}}, i64 16) 63; SSI-NOT: @llvm.aarch64.tagp 64; SSI-NOT: @llvm.aarch64.settag 65 66; CHECK: call void @use32( 67; CHECK: call void @use8( 68; CHECK: call void @use32( 69 70; CHECK: call void @llvm.aarch64.settag(i8* {{.*}}, i64 16) 71; CHECK: call void @llvm.aarch64.settag(i8* {{.*}}, i64 16) 72; CHECK: call void @llvm.aarch64.settag(i8* {{.*}}, i64 48) 73; NOSSI: call void @llvm.aarch64.settag(i8* {{.*}}, i64 16) 74; CHECK-NEXT: ret void 75 76 77define void @Scope(i32 %b) sanitize_memtag { 78entry: 79 %x = alloca i32, align 4 80 %tobool = icmp eq i32 %b, 0 81 br i1 %tobool, label %if.end, label %if.then 82 83if.then: 84 %0 = bitcast i32* %x to i8* 85 call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %0) 86 call void @use8(i8* %0) #3 87 call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %0) 88 br label %if.end 89 90if.end: 91 ret void 92} 93 94; CHECK-LABEL: define void @Scope( 95; CHECK: br i1 96; CHECK: call void @llvm.lifetime.start.p0i8( 97; CHECK: call void @llvm.aarch64.settag( 98; CHECK: call void @use8( 99; CHECK: call void @llvm.aarch64.settag( 100; CHECK: call void @llvm.lifetime.end.p0i8( 101; CHECK: br label 102; CHECK: ret void 103 104 105; Spooked by the multiple lifetime ranges, StackTagging remove all of them and sets tags on entry and exit. 106define void @BadScope(i32 %b) sanitize_memtag { 107entry: 108 %x = alloca i32, align 4 109 %tobool = icmp eq i32 %b, 0 110 br i1 %tobool, label %if.end, label %if.then 111 112if.then: 113 %0 = bitcast i32* %x to i8* 114 call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %0) 115 call void @use8(i8* %0) #3 116 call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %0) 117 118 call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %0) 119 call void @use8(i8* %0) #3 120 call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %0) 121 br label %if.end 122 123if.end: 124 ret void 125} 126 127; CHECK-LABEL: define void @BadScope( 128; CHECK: call void @llvm.aarch64.settag(i8* {{.*}}, i64 16) 129; CHECK: br i1 130; CHECK: call void @use8(i8* 131; CHECK-NEXT: call void @use8(i8* 132; CHECK: br label 133; CHECK: call void @llvm.aarch64.settag(i8* {{.*}}, i64 16) 134; CHECK-NEXT: ret void 135 136define void @DynamicAllocas(i32 %cnt) sanitize_memtag { 137entry: 138 %x = alloca i32, i32 %cnt, align 4 139 br label %l 140l: 141 %y = alloca i32, align 4 142 call void @use32(i32* %x) 143 call void @use32(i32* %y) 144 ret void 145} 146 147; CHECK-LABEL: define void @DynamicAllocas( 148; CHECK-NOT: @llvm.aarch64.irg.sp 149; CHECK: %x = alloca i32, i32 %cnt, align 4 150; CHECK-NOT: @llvm.aarch64.irg.sp 151; CHECK: alloca i32, align 4 152; CHECK-NOT: @llvm.aarch64.irg.sp 153; CHECK: ret void 154 155; If we can't trace one of the lifetime markers to a single alloca, fall back 156; to poisoning all allocas at the beginning of the function. 157; Each alloca must be poisoned only once. 158define void @UnrecognizedLifetime(i8 %v) sanitize_memtag { 159entry: 160 %x = alloca i32, align 4 161 %y = alloca i32, align 4 162 %z = alloca i32, align 4 163 %cx = bitcast i32* %x to i8* 164 %cy = bitcast i32* %y to i8* 165 %cz = bitcast i32* %z to i8* 166 %tobool = icmp eq i8 %v, 0 167 %xy = select i1 %tobool, i32* %x, i32* %y 168 %cxcy = select i1 %tobool, i8* %cx, i8* %cy 169 br label %another_bb 170 171another_bb: 172 call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %cz) 173 store i32 7, i32* %z 174 call void @noUse32(i32* %z) 175 call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %cz) 176 call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %cz) 177 store i32 7, i32* %z 178 call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %cz) 179 call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %cxcy) 180 store i32 8, i32* %xy 181 call void @noUse32(i32* %x) 182 call void @noUse32(i32* %y) 183 call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %cxcy) 184 ret void 185} 186 187; CHECK-LABEL: define void @UnrecognizedLifetime( 188; CHECK: call i8* @llvm.aarch64.irg.sp(i64 0) 189; CHECK: alloca { i32, [12 x i8] }, align 16 190; CHECK: call { i32, [12 x i8] }* @llvm.aarch64.tagp 191; CHECK: call void @llvm.aarch64.settag( 192; CHECK: alloca { i32, [12 x i8] }, align 16 193; CHECK: call { i32, [12 x i8] }* @llvm.aarch64.tagp 194; CHECK: call void @llvm.aarch64.settag( 195; SSI: alloca i32, align 4 196; NOSSI: alloca { i32, [12 x i8] }, align 16 197; NOSSI: call { i32, [12 x i8] }* @llvm.aarch64.tagp 198; NOSSI: call void @llvm.aarch64.settag( 199; CHECK: store i32 200; CHECK: call void @noUse32(i32* 201; CHECK: store i32 202; CHECK: store i32 203; CHECK: call void @noUse32(i32* 204; CHECK: call void @llvm.aarch64.settag( 205; CHECK: call void @llvm.aarch64.settag( 206; NOSSI: call void @llvm.aarch64.settag( 207; CHECK: ret void 208 209!0 = !{}