| 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 |
| 4 | void 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 |
| 32 | void 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 |
| 56 | void 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 |
| 78 | void 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 |
| 103 | void 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 |
| 117 | void 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 |
| 128 | void 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 |
| 139 | void 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 | |
| 147 | struct 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 |
| 160 | void 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 | |
| 172 | typedef void (*funcptr_t)(void); |
| 173 | |
| 174 | // CHECK-LABEL: define void @function_pointer_arith |
| 175 | void 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 |
| 188 | void 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 |
| 206 | void 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 |
| 215 | void dont_emit_checks_for_no_op_GEPs(char *p) { |
| 216 | &p[0]; |
| 217 | |
| 218 | int arr[10][10]; |
| 219 | &arr[0][0]; |
| 220 | } |
| 221 | |