1// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -w -emit-llvm -o - %s -fsanitize=pointer-overflow | FileCheck %s 2 3// CHECK-LABEL: define void @unary_arith 4void unary_arith(char *p) { 5 // CHECK: [[BASE:%.*]] = ptrtoint i8* {{.*}} to i64, !nosanitize 6 // CHECK-NEXT: [[COMPGEP:%.*]] = add i64 [[BASE]], 1, !nosanitize 7 // CHECK-NEXT: [[POSVALID:%.*]] = icmp uge i64 [[COMPGEP]], [[BASE]], !nosanitize 8 // CHECK-NEXT: br i1 [[POSVALID]]{{.*}}, !nosanitize 9 // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}, i64 [[BASE]], i64 [[COMPGEP]]){{.*}}, !nosanitize 10 ++p; 11 12 // CHECK: ptrtoint i8* {{.*}} to i64, !nosanitize 13 // CHECK-NEXT: [[COMPGEP:%.*]] = add i64 {{.*}}, -1, !nosanitize 14 // CHECK: [[NEGVALID:%.*]] = icmp ule i64 [[COMPGEP]], {{.*}}, !nosanitize 15 // CHECK-NOT: select 16 // CHECK: br i1 [[NEGVALID]]{{.*}}, !nosanitize 17 // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}} 18 --p; 19 20 // CHECK: icmp uge i64 21 // CHECK-NOT: select 22 // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}} 23 p++; 24 25 // CHECK: icmp ule i64 26 // CHECK-NOT: select 27 // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}} 28 p--; 29} 30 31// CHECK-LABEL: define void @binary_arith 32void binary_arith(char *p, int i) { 33 // CHECK: [[SMUL:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 1, i64 %{{.*}}), !nosanitize 34 // CHECK-NEXT: [[SMULOFLOW:%.*]] = extractvalue { i64, i1 } [[SMUL]], 1, !nosanitize 35 // CHECK-NEXT: [[SMULVAL:%.*]] = extractvalue { i64, i1 } [[SMUL]], 0, !nosanitize 36 // CHECK-NEXT: [[BASE:%.*]] = ptrtoint i8* {{.*}} to i64, !nosanitize 37 // CHECK-NEXT: [[COMPGEP:%.*]] = add i64 [[BASE]], [[SMULVAL]], !nosanitize 38 // CHECK-NEXT: [[OFFSETVALID:%.*]] = xor i1 [[SMULOFLOW]], true, !nosanitize 39 // CHECK-NEXT: [[POSVALID:%.*]] = icmp uge i64 [[COMPGEP]], [[BASE]], !nosanitize 40 // CHECK-NEXT: [[POSOFFSET:%.*]] = icmp sge i64 [[SMULVAL]], 0, !nosanitize 41 // CHECK-NEXT: [[NEGVALID:%.*]] = icmp ult i64 [[COMPGEP]], [[BASE]], !nosanitize 42 // CHECK-NEXT: [[DIFFVALID:%.*]] = select i1 [[POSOFFSET]], i1 [[POSVALID]], i1 [[NEGVALID]], !nosanitize 43 // CHECK: [[VALID:%.*]] = and i1 [[DIFFVALID]], [[OFFSETVALID]], !nosanitize 44 // CHECK-NEXT: br i1 [[VALID]]{{.*}}, !nosanitize 45 // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}, i64 [[BASE]], i64 [[COMPGEP]]){{.*}}, !nosanitize 46 p + i; 47 48 // CHECK: [[OFFSET:%.*]] = sub i64 0, {{.*}} 49 // CHECK-NEXT: getelementptr inbounds {{.*}} [[OFFSET]] 50 // CHECK: select 51 // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}} 52 p - i; 53} 54 55// CHECK-LABEL: define void @binary_arith_unsigned 56void binary_arith_unsigned(char *p, unsigned i) { 57 // CHECK: [[SMUL:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 1, i64 %{{.*}}), !nosanitize 58 // CHECK-NEXT: [[SMULOFLOW:%.*]] = extractvalue { i64, i1 } [[SMUL]], 1, !nosanitize 59 // CHECK-NEXT: [[SMULVAL:%.*]] = extractvalue { i64, i1 } [[SMUL]], 0, !nosanitize 60 // CHECK-NEXT: [[BASE:%.*]] = ptrtoint i8* {{.*}} to i64, !nosanitize 61 // CHECK-NEXT: [[COMPGEP:%.*]] = add i64 [[BASE]], [[SMULVAL]], !nosanitize 62 // CHECK-NEXT: [[OFFSETVALID:%.*]] = xor i1 [[SMULOFLOW]], true, !nosanitize 63 // CHECK-NEXT: [[POSVALID:%.*]] = icmp uge i64 [[COMPGEP]], [[BASE]], !nosanitize 64 // CHECK: [[VALID:%.*]] = and i1 [[POSVALID]], [[OFFSETVALID]], !nosanitize 65 // CHECK-NEXT: br i1 [[VALID]]{{.*}}, !nosanitize 66 // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}, i64 [[BASE]], i64 [[COMPGEP]]){{.*}}, !nosanitize 67 p + i; 68 69 // CHECK: [[OFFSET:%.*]] = sub i64 0, {{.*}} 70 // CHECK-NEXT: getelementptr inbounds {{.*}} [[OFFSET]] 71 // CHECK: icmp ule i64 72 // CHECK-NOT: select 73 // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}} 74 p - i; 75} 76 77// CHECK-LABEL: define void @fixed_len_array 78void fixed_len_array(int k) { 79 // CHECK: getelementptr inbounds [10 x [10 x i32]], [10 x [10 x i32]]* [[ARR:%.*]], i64 0, i64 [[IDXPROM:%.*]] 80 // CHECK-NEXT: [[SMUL:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 40, i64 [[IDXPROM]]), !nosanitize 81 // CHECK-NEXT: [[SMULOFLOW:%.*]] = extractvalue { i64, i1 } [[SMUL]], 1, !nosanitize 82 // CHECK-NEXT: [[SMULVAL:%.*]] = extractvalue { i64, i1 } [[SMUL]], 0, !nosanitize 83 // CHECK-NEXT: [[BASE:%.*]] = ptrtoint [10 x [10 x i32]]* [[ARR]] to i64, !nosanitize 84 // CHECK-NEXT: [[COMPGEP:%.*]] = add i64 [[BASE]], [[SMULVAL]], !nosanitize 85 // CHECK-NEXT: [[OFFSETVALID:%.*]] = xor i1 [[SMULOFLOW]], true, !nosanitize 86 // CHECK-NEXT: [[POSVALID:%.*]] = icmp uge i64 [[COMPGEP]], [[BASE]], !nosanitize 87 // CHECK-NEXT: [[POSOFFSET:%.*]] = icmp sge i64 [[SMULVAL]], 0, !nosanitize 88 // CHECK-NEXT: [[NEGVALID:%.*]] = icmp ult i64 [[COMPGEP]], [[BASE]], !nosanitize 89 // CHECK-NEXT: [[DIFFVALID:%.*]] = select i1 [[POSOFFSET]], i1 [[POSVALID]], i1 [[NEGVALID]], !nosanitize 90 // CHECK: [[VALID:%.*]] = and i1 [[DIFFVALID]], [[OFFSETVALID]], !nosanitize 91 // CHECK-NEXT: br i1 [[VALID]]{{.*}}, !nosanitize 92 // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}}, i64 [[BASE]], i64 [[COMPGEP]]){{.*}}, !nosanitize 93 94 // CHECK: getelementptr inbounds [10 x i32], [10 x i32]* {{.*}}, i64 0, i64 [[IDXPROM1:%.*]] 95 // CHECK-NEXT: @llvm.smul.with.overflow.i64(i64 4, i64 [[IDXPROM1]]), !nosanitize 96 // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}} 97 98 int arr[10][10]; 99 arr[k][k]; 100} 101 102// CHECK-LABEL: define void @variable_len_array 103void variable_len_array(int n, int k) { 104 // CHECK: getelementptr inbounds i32, i32* {{.*}}, i64 [[IDXPROM:%.*]] 105 // CHECK-NEXT: @llvm.smul.with.overflow.i64(i64 4, i64 [[IDXPROM]]), !nosanitize 106 // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}} 107 108 // CHECK: getelementptr inbounds i32, i32* {{.*}}, i64 [[IDXPROM1:%.*]] 109 // CHECK-NEXT: @llvm.smul.with.overflow.i64(i64 4, i64 [[IDXPROM1]]), !nosanitize 110 // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}} 111 112 int arr[n][n]; 113 arr[k][k]; 114} 115 116// CHECK-LABEL: define void @pointer_array 117void pointer_array(int **arr, int k) { 118 // CHECK: @llvm.smul.with.overflow.i64(i64 8, i64 {{.*}}), !nosanitize 119 // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}} 120 121 // CHECK: @llvm.smul.with.overflow.i64(i64 4, i64 {{.*}}), !nosanitize 122 // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}} 123 124 arr[k][k]; 125} 126 127// CHECK-LABEL: define void @pointer_array_unsigned_indices 128void pointer_array_unsigned_indices(int **arr, unsigned k) { 129 // CHECK: icmp uge 130 // CHECK-NOT: select 131 // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}} 132 // CHECK: icmp uge 133 // CHECK-NOT: select 134 // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}} 135 arr[k][k]; 136} 137 138// CHECK-LABEL: define void @pointer_array_mixed_indices 139void pointer_array_mixed_indices(int **arr, int i, unsigned j) { 140 // CHECK: select 141 // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}} 142 // CHECK-NOT: select 143 // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}} 144 arr[i][j]; 145} 146 147struct S1 { 148 int pad1; 149 union { 150 char leaf; 151 struct S1 *link; 152 } u; 153 struct S1 *arr; 154}; 155 156// TODO: Currently, structure GEPs are not checked, so there are several 157// potentially unsafe GEPs here which we don't instrument. 158// 159// CHECK-LABEL: define void @struct_index 160void struct_index(struct S1 *p) { 161 // CHECK: getelementptr inbounds %struct.S1, %struct.S1* [[P:%.*]], i64 10 162 // CHECK-NEXT: [[BASE:%.*]] = ptrtoint %struct.S1* [[P]] to i64, !nosanitize 163 // CHECK-NEXT: [[COMPGEP:%.*]] = add i64 [[BASE]], 240, !nosanitize 164 // CHECK: select 165 // CHECK: @__ubsan_handle_pointer_overflow{{.*}} i64 [[BASE]], i64 [[COMPGEP]]) {{.*}}, !nosanitize 166 167 // CHECK-NOT: @__ubsan_handle_pointer_overflow 168 169 p->arr[10].u.link->u.leaf; 170} 171 172typedef void (*funcptr_t)(void); 173 174// CHECK-LABEL: define void @function_pointer_arith 175void function_pointer_arith(funcptr_t *p, int k) { 176 // CHECK: add i64 {{.*}}, 8, !nosanitize 177 // CHECK-NOT: select 178 // CHECK: @__ubsan_handle_pointer_overflow{{.*}} 179 ++p; 180 181 // CHECK: @llvm.smul.with.overflow.i64(i64 8, i64 {{.*}}), !nosanitize 182 // CHECK: select 183 // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}} 184 p + k; 185} 186 187// CHECK-LABEL: define void @variable_len_array_arith 188void variable_len_array_arith(int n, int k) { 189 int vla[n]; 190 int (*p)[n] = &vla; 191 192 // CHECK: getelementptr inbounds i32, i32* {{.*}}, i64 [[INC:%.*]] 193 // CHECK: @llvm.smul.with.overflow.i64(i64 4, i64 [[INC]]), !nosanitize 194 // CHECK-NOT: select 195 // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}} 196 ++p; 197 198 // CHECK: getelementptr inbounds i32, i32* {{.*}}, i64 [[IDXPROM:%.*]] 199 // CHECK: @llvm.smul.with.overflow.i64(i64 4, i64 [[IDXPROM]]), !nosanitize 200 // CHECK: select 201 // CHECK: call void @__ubsan_handle_pointer_overflow{{.*}} 202 p + k; 203} 204 205// CHECK-LABEL: define void @objc_id 206void objc_id(id *p) { 207 // CHECK: add i64 {{.*}}, 8, !nosanitize 208 // CHECK-NOT: select 209 // CHECK: @__ubsan_handle_pointer_overflow{{.*}} 210 p++; 211} 212 213// CHECK-LABEL: define void @dont_emit_checks_for_no_op_GEPs 214// CHECK-NOT: __ubsan_handle_pointer_overflow 215void dont_emit_checks_for_no_op_GEPs(char *p) { 216 &p[0]; 217 218 int arr[10][10]; 219 &arr[0][0]; 220} 221