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