1; 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 3 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) 175