1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
|
// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \
// RUN: -fsafe-buffer-usage-suggestions \
// RUN: -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
typedef int * Int_ptr_t;
typedef int Int_t;
void simple(unsigned idx) {
int buffer[10];
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:17}:"std::array<int, 10> buffer"
buffer[idx] = 0;
}
void array2d(unsigned idx) {
int buffer[10][10];
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]
buffer[idx][idx] = 0;
}
void array2d_vla(unsigned sz, unsigned idx) {
int buffer1[10][sz];
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]
int buffer2[sz][10];
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]
buffer1[idx][idx] = 0;
buffer2[idx][idx] = 0;
}
void array2d_assign_from_elem(unsigned idx) {
int buffer[10][10];
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]
int a = buffer[idx][idx];
}
void array2d_use(int *);
void array2d_call(unsigned idx) {
int buffer[10][10];
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]
array2d_use(buffer[idx]);
}
void array2d_call_vla(unsigned sz, unsigned idx) {
int buffer[10][sz];
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]
array2d_use(buffer[idx]);
}
void array2d_typedef(unsigned idx) {
typedef int ten_ints_t[10];
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]
ten_ints_t buffer[10];
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]
buffer[idx][idx] = 0;
}
void whitespace_in_declaration(unsigned idx) {
int buffer_w [ 10 ];
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:35}:"std::array<int, 10> buffer_w"
buffer_w[idx] = 0;
}
void comments_in_declaration(unsigned idx) {
int /* [A] */ buffer_w /* [B] */ [ /* [C] */ 10 /* [D] */ ] ;
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:69}:"std::array<int /* [A] */, /* [C] */ 10 /* [D] */> buffer_w"
buffer_w[idx] = 0;
}
void initializer(unsigned idx) {
int buffer[3] = {0};
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:16}:"std::array<int, 3> buffer"
int buffer2[3] = {0, 1, 2};
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:17}:"std::array<int, 3> buffer2"
buffer[idx] = 0;
buffer2[idx] = 0;
}
void auto_size(unsigned idx) {
int buffer[] = {0, 1, 2};
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]
// FIXME: implement support
buffer[idx] = 0;
}
void universal_initialization(unsigned idx) {
int buffer[] {0, 1, 2};
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]
// FIXME: implement support
buffer[idx] = 0;
}
void multi_decl1(unsigned idx) {
int a, buffer[10];
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]
// FIXME: implement support
buffer[idx] = 0;
}
void multi_decl2(unsigned idx) {
int buffer[10], b;
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]
// FIXME: implement support
buffer[idx] = 0;
}
void local_array_ptr_to_const(unsigned idx, const int*& a) {
const int * buffer[10] = {a};
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:25}:"std::array<const int *, 10> buffer"
a = buffer[idx];
}
void local_array_const_ptr(unsigned idx, int*& a) {
int * const buffer[10] = {a};
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:25}:"std::array<int * const, 10> buffer"
a = buffer[idx];
}
void local_array_const_ptr_via_typedef(unsigned idx, int*& a) {
typedef int * const my_const_ptr;
my_const_ptr buffer[10] = {a};
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:26}:"std::array<my_const_ptr, 10> buffer"
a = buffer[idx];
}
void local_array_const_ptr_to_const(unsigned idx, const int*& a) {
const int * const buffer[10] = {a};
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:31}:"std::array<const int * const, 10> buffer"
a = buffer[idx];
}
template<typename T>
void unsupported_local_array_in_template(unsigned idx) {
T buffer[10];
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:.*-[[@LINE-1]]:.*}
buffer[idx] = 0;
}
// Instantiate the template function to force its analysis.
template void unsupported_local_array_in_template<int>(unsigned);
typedef unsigned int my_uint;
void typedef_as_elem_type(unsigned idx) {
my_uint buffer[10];
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:21}:"std::array<my_uint, 10> buffer"
buffer[idx] = 0;
}
void decltype_as_elem_type(unsigned idx) {
int a;
decltype(a) buffer[10];
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:25}:"std::array<decltype(a), 10> buffer"
buffer[idx] = 0;
}
void macro_as_elem_type(unsigned idx) {
#define MY_INT int
MY_INT buffer[10];
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:.*-[[@LINE-1]]:.*}
// FIXME: implement support
buffer[idx] = 0;
#undef MY_INT
}
void macro_as_identifier(unsigned idx) {
#define MY_BUFFER buffer
int MY_BUFFER[10];
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:20}:"std::array<int, 10> MY_BUFFER"
MY_BUFFER[idx] = 0;
#undef MY_BUFFER
}
void macro_as_size(unsigned idx) {
#define MY_TEN 10
int buffer[MY_TEN];
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:21}:"std::array<int, MY_TEN> buffer"
buffer[idx] = 0;
#undef MY_TEN
}
typedef unsigned int my_array[42];
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:.*-[[@LINE-1]]:.*}
void typedef_as_array_type(unsigned idx) {
my_array buffer;
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:.*-[[@LINE-1]]:.*}
buffer[idx] = 0;
}
void decltype_as_array_type(unsigned idx) {
int buffer[42];
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:.*-[[@LINE-1]]:.*}
decltype(buffer) buffer2;
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:.*-[[@LINE-1]]:.*}
buffer2[idx] = 0;
}
void constant_as_size(unsigned idx) {
const unsigned my_const = 10;
int buffer[my_const];
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:23}:"std::array<int, my_const> buffer"
buffer[idx] = 0;
}
void subscript_negative() {
int buffer[10];
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:17}:"std::array<int, 10> buffer"
// For constant-size arrays any negative index will lead to buffer underflow.
// std::array::operator[] has unsigned parameter so the value will be casted to unsigned.
// This will very likely be buffer overflow but hardened std::array catch these at runtime.
buffer[-5] = 0;
}
void subscript_signed(int signed_idx) {
int buffer[10];
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:17}:"std::array<int, 10> buffer"
// For constant-size arrays any negative index will lead to buffer underflow.
// std::array::operator[] has unsigned parameter so the value will be casted to unsigned.
// This will very likely be buffer overflow but hardened std::array catches these at runtime.
buffer[signed_idx] = 0;
}
|