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