1 // RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage \ 2 // RUN: -fsafe-buffer-usage-suggestions \ 3 // RUN: -fblocks -include %s -verify %s 4 5 // RUN: %clang -x c++ -fsyntax-only -fblocks -include %s %s 2>&1 | FileCheck --allow-empty %s 6 // RUN: %clang_cc1 -std=c++11 -fblocks -include %s %s 2>&1 | FileCheck --allow-empty %s 7 // RUN: %clang_cc1 -std=c++20 -fblocks -include %s %s 2>&1 | FileCheck --allow-empty %s 8 // CHECK-NOT: [-Wunsafe-buffer-usage] 9 10 #ifndef INCLUDED 11 #define INCLUDED 12 #pragma clang system_header 13 14 // no spanification warnings for system headers 15 void foo(...); // let arguments of `foo` to hold testing expressions 16 void testAsSystemHeader(char *p) { 17 ++p; 18 19 auto ap1 = p; 20 auto ap2 = &p; 21 22 foo(p[1], 23 ap1[1], 24 ap2[2][3]); 25 } 26 27 #else 28 29 void testIncrement(char *p) { // expected-warning{{'p' is an unsafe pointer used for buffer access}} 30 ++p; // expected-note{{used in pointer arithmetic here}} 31 p++; // expected-note{{used in pointer arithmetic here}} 32 --p; // expected-note{{used in pointer arithmetic here}} 33 p--; // expected-note{{used in pointer arithmetic here}} 34 } 35 36 void * voidPtrCall(void); 37 char * charPtrCall(void); 38 39 void testArraySubscripts(int idx, int *p, int **pp) { 40 // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} 41 // expected-warning@-2{{'pp' is an unsafe pointer used for buffer access}} 42 foo(p[1], // expected-note{{used in buffer access here}} 43 pp[1][1], // expected-note{{used in buffer access here}} 44 // expected-warning@-1{{unsafe buffer access}} 45 1[1[pp]], // expected-note{{used in buffer access here}} 46 // expected-warning@-1{{unsafe buffer access}} 47 1[pp][1] // expected-note{{used in buffer access here}} 48 // expected-warning@-1{{unsafe buffer access}} 49 ); 50 51 if (p[3]) { // expected-note{{used in buffer access here}} 52 void * q = p; 53 54 foo(((int*)q)[10]); // expected-warning{{unsafe buffer access}} 55 } 56 57 foo(((int*)voidPtrCall())[3], // expected-warning{{unsafe buffer access}} 58 3[(int*)voidPtrCall()], // expected-warning{{unsafe buffer access}} 59 charPtrCall()[3], // expected-warning{{unsafe buffer access}} 60 3[charPtrCall()] // expected-warning{{unsafe buffer access}} 61 ); 62 63 int a[10]; // expected-warning{{'a' is an unsafe buffer that does not perform bounds checks}} 64 // expected-note@-1{{change type of 'a' to 'std::array' to label it for hardening}} 65 int b[10][10]; // expected-warning{{'b' is an unsafe buffer that does not perform bounds checks}} 66 67 foo(a[idx], idx[a], // expected-note2{{used in buffer access here}} 68 b[idx][idx + 1], // expected-warning{{unsafe buffer access}} 69 // expected-note@-1{{used in buffer access here}} 70 (idx + 1)[b][idx],// expected-warning{{unsafe buffer access}} 71 // expected-note@-1{{used in buffer access here}} 72 (idx + 1)[idx[b]]); 73 // expected-warning@-1{{unsafe buffer access}} 74 // expected-note@-2{{used in buffer access here}} 75 76 // Not to warn when index is zero 77 foo(p[0], pp[0][0], 0[0[pp]], 0[pp][0], 78 ((int*)voidPtrCall())[0], 79 0[(int*)voidPtrCall()], 80 charPtrCall()[0], 81 0[charPtrCall()] 82 ); 83 } 84 85 void testArraySubscriptsWithAuto() { 86 int a[10]; 87 // We do not fix a declaration if the type is `auto`. Because the actual type may change later. 88 auto ap1 = a; // expected-warning{{'ap1' is an unsafe pointer used for buffer access}} 89 foo(ap1[1]); // expected-note{{used in buffer access here}} 90 91 // In case the type is `auto *`, we know it must be a pointer. We can fix it. 92 auto * ap2 = a; // expected-warning{{'ap2' is an unsafe pointer used for buffer access}} \ 93 expected-note{{change type of 'ap2' to 'std::span' to preserve bounds information}} 94 foo(ap2[1]); // expected-note{{used in buffer access here}} 95 } 96 97 void testUnevaluatedContext(int * p) {// no-warning 98 foo(sizeof(p[1]), // no-warning 99 sizeof(decltype(p[1]))); // no-warning 100 } 101 102 void testQualifiedParameters(const int * p, const int * const q, const int a[10], const int b[10][10]) { 103 // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} 104 // expected-warning@-2{{'q' is an unsafe pointer used for buffer access}} 105 // expected-warning@-3{{'a' is an unsafe pointer used for buffer access}} 106 // expected-warning@-4{{'b' is an unsafe pointer used for buffer access}} 107 108 foo(p[1], 1[p], p[-1], // expected-note3{{used in buffer access here}} 109 q[1], 1[q], q[-1], // expected-note3{{used in buffer access here}} 110 a[1], // expected-note{{used in buffer access here}} `a` is of pointer type 111 b[1][2] // expected-note{{used in buffer access here}} `b[1]` is of array type 112 // expected-warning@-1{{unsafe buffer access}} 113 ); 114 } 115 116 struct T { 117 int a[10]; 118 int * b; 119 struct { 120 int a[10]; 121 int * b; 122 } c; 123 }; 124 125 typedef struct T T_t; 126 127 T_t funRetT(); 128 T_t * funRetTStar(); 129 130 void testStructMembers(struct T * sp, struct T s, T_t * sp2, T_t s2) { 131 foo(sp->a[1], // expected-warning{{unsafe buffer access}} 132 sp->b[1], // expected-warning{{unsafe buffer access}} 133 sp->c.a[1], // expected-warning{{unsafe buffer access}} 134 sp->c.b[1], // expected-warning{{unsafe buffer access}} 135 s.a[1], // expected-warning{{unsafe buffer access}} 136 s.b[1], // expected-warning{{unsafe buffer access}} 137 s.c.a[1], // expected-warning{{unsafe buffer access}} 138 s.c.b[1], // expected-warning{{unsafe buffer access}} 139 sp2->a[1], // expected-warning{{unsafe buffer access}} 140 sp2->b[1], // expected-warning{{unsafe buffer access}} 141 sp2->c.a[1], // expected-warning{{unsafe buffer access}} 142 sp2->c.b[1], // expected-warning{{unsafe buffer access}} 143 s2.a[1], // expected-warning{{unsafe buffer access}} 144 s2.b[1], // expected-warning{{unsafe buffer access}} 145 s2.c.a[1], // expected-warning{{unsafe buffer access}} 146 s2.c.b[1], // expected-warning{{unsafe buffer access}} 147 funRetT().a[1], // expected-warning{{unsafe buffer access}} 148 funRetT().b[1], // expected-warning{{unsafe buffer access}} 149 funRetTStar()->a[1], // expected-warning{{unsafe buffer access}} 150 funRetTStar()->b[1] // expected-warning{{unsafe buffer access}} 151 ); 152 } 153 154 int garray[10]; // expected-warning{{'garray' is an unsafe buffer that does not perform bounds checks}} 155 int * gp = garray; // expected-warning{{'gp' is an unsafe pointer used for buffer access}} 156 int gvar = gp[1]; // FIXME: file scope unsafe buffer access is not warned 157 158 void testLambdaCaptureAndGlobal(int * p) { 159 // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} 160 int a[10]; // expected-warning{{'a' is an unsafe buffer that does not perform bounds checks}} 161 162 auto Lam = [p, a](int idx) { 163 return p[1] // expected-note{{used in buffer access here}} 164 + a[idx] + garray[idx]// expected-note2{{used in buffer access here}} 165 + gp[1]; // expected-note{{used in buffer access here}} 166 167 }; 168 } 169 170 auto file_scope_lambda = [](int *ptr) { 171 // expected-warning@-1{{'ptr' is an unsafe pointer used for buffer access}} 172 173 ptr[5] = 10; // expected-note{{used in buffer access here}} 174 }; 175 176 void testLambdaCapture() { 177 int a[10]; // expected-warning{{'a' is an unsafe buffer that does not perform bounds checks}} 178 int b[10]; // expected-warning{{'b' is an unsafe buffer that does not perform bounds checks}} 179 // expected-note@-1{{change type of 'b' to 'std::array' to label it for hardening}} 180 int c[10]; 181 182 auto Lam1 = [a](unsigned idx) { 183 return a[idx]; // expected-note{{used in buffer access here}} 184 }; 185 186 auto Lam2 = [x = b[c[5]]]() { // expected-note{{used in buffer access here}} 187 return x; 188 }; 189 190 auto Lam = [x = c](unsigned idx) { // expected-warning{{'x' is an unsafe pointer used for buffer access}} 191 return x[idx]; // expected-note{{used in buffer access here}} 192 }; 193 } 194 195 void testLambdaImplicitCapture(long idx) { 196 int a[10]; // expected-warning{{'a' is an unsafe buffer that does not perform bounds checks}} 197 // expected-note@-1{{change type of 'a' to 'std::array' to label it for hardening}} 198 int b[10]; // expected-warning{{'b' is an unsafe buffer that does not perform bounds checks}} 199 // expected-note@-1{{change type of 'b' to 'std::array' to label it for hardening}} 200 201 auto Lam1 = [=]() { 202 return a[idx]; // expected-note{{used in buffer access here}} 203 }; 204 205 auto Lam2 = [&]() { 206 return b[idx]; // expected-note{{used in buffer access here}} 207 }; 208 } 209 210 typedef T_t * T_ptr_t; 211 212 void testTypedefs(T_ptr_t p) { 213 // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} 214 foo(p[1], // expected-note{{used in buffer access here}} 215 p[1].a[1], // expected-note{{used in buffer access here}} 216 // expected-warning@-1{{unsafe buffer access}} 217 p[1].b[1] // expected-note{{used in buffer access here}} 218 // expected-warning@-1{{unsafe buffer access}} 219 ); 220 } 221 222 template<typename T, int N> T f(T t, T * pt, T a[N], T (&b)[N]) { 223 // expected-warning@-1{{'t' is an unsafe pointer used for buffer access}} 224 // expected-warning@-2{{'pt' is an unsafe pointer used for buffer access}} 225 // expected-warning@-3{{'a' is an unsafe pointer used for buffer access}} 226 // expected-warning@-4{{'b' is an unsafe buffer that does not perform bounds checks}} 227 foo(pt[1], // expected-note{{used in buffer access here}} 228 a[1], // expected-note{{used in buffer access here}} 229 b[1]); // expected-note{{used in buffer access here}} 230 return &t[1]; // expected-note{{used in buffer access here}} 231 } 232 233 // Testing pointer arithmetic for pointer-to-int, qualified multi-level 234 // pointer, pointer to a template type, and auto type 235 T_ptr_t getPtr(); 236 237 template<typename T> 238 void testPointerArithmetic(int * p, const int **q, T * x) { 239 // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} 240 // expected-warning@-2{{'x' is an unsafe pointer used for buffer access}} 241 int a[10]; 242 auto y = &a[0]; // expected-warning{{'y' is an unsafe pointer used for buffer access}} 243 244 foo(p + 1, 1 + p, p - 1, // expected-note3{{used in pointer arithmetic here}} 245 *q + 1, 1 + *q, *q - 1, // expected-warning3{{unsafe pointer arithmetic}} 246 x + 1, 1 + x, x - 1, // expected-note3{{used in pointer arithmetic here}} 247 y + 1, 1 + y, y - 1, // expected-note3{{used in pointer arithmetic here}} 248 getPtr() + 1, 1 + getPtr(), getPtr() - 1 // expected-warning3{{unsafe pointer arithmetic}} 249 ); 250 251 p += 1; p -= 1; // expected-note2{{used in pointer arithmetic here}} 252 *q += 1; *q -= 1; // expected-warning2{{unsafe pointer arithmetic}} 253 y += 1; y -= 1; // expected-note2{{used in pointer arithmetic here}} 254 x += 1; x -= 1; // expected-note2{{used in pointer arithmetic here}} 255 } 256 257 void testTemplate(int * p) { 258 int *a[10]; 259 foo(f(p, &p, a, a)[1]); // expected-warning{{unsafe buffer access}} 260 // FIXME: expected note@-1{{in instantiation of function template specialization 'f<int *, 10>' requested here}} 261 262 const int **q = const_cast<const int **>(&p); 263 264 testPointerArithmetic(p, q, p); //FIXME: expected note{{in instantiation of}} 265 } 266 267 void testPointerToMember() { 268 struct S_t { 269 int x; 270 int * y; 271 } S; 272 273 int S_t::* p = &S_t::x; 274 int * S_t::* q = &S_t::y; 275 276 foo(S.*p, 277 (S.*q)[1]); // expected-warning{{unsafe buffer access}} 278 } 279 280 // test that nested callable definitions are scanned only once 281 void testNestedCallableDefinition(int * p) { 282 class A { 283 void inner(int * p) { 284 // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} 285 p++; // expected-note{{used in pointer arithmetic here}} 286 } 287 288 static void innerStatic(int * p) { 289 // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} 290 p++; // expected-note{{used in pointer arithmetic here}} 291 } 292 293 void innerInner(int * p) { 294 auto Lam = [p]() { 295 int * q = p; // expected-warning{{'q' is an unsafe pointer used for buffer access}} 296 q++; // expected-note{{used in pointer arithmetic here}} 297 return *q; 298 }; 299 } 300 }; 301 302 auto Lam = [p]() { 303 int * q = p; // expected-warning{{'q' is an unsafe pointer used for buffer access}} 304 q++; // expected-note{{used in pointer arithmetic here}} 305 return *q; 306 }; 307 308 auto LamLam = [p]() { 309 auto Lam = [p]() { 310 int * q = p; // expected-warning{{'q' is an unsafe pointer used for buffer access}} 311 q++; // expected-note{{used in pointer arithmetic here}} 312 return *q; 313 }; 314 }; 315 316 void (^Blk)(int*) = ^(int *p) { 317 // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} 318 p++; // expected-note{{used in pointer arithmetic here}} 319 }; 320 321 void (^BlkBlk)(int*) = ^(int *p) { 322 void (^Blk)(int*) = ^(int *p) { 323 // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} 324 p++; // expected-note{{used in pointer arithmetic here}} 325 }; 326 Blk(p); 327 }; 328 329 // lambda and block as call arguments... 330 foo( [p]() { int * q = p; // expected-warning{{'q' is an unsafe pointer used for buffer access}} 331 q++; // expected-note{{used in pointer arithmetic here}} 332 return *q; 333 }, 334 ^(int *p) { // expected-warning{{'p' is an unsafe pointer used for buffer access}} 335 p++; // expected-note{{used in pointer arithmetic here}} 336 } 337 ); 338 } 339 340 int testVariableDecls(int * p) { 341 // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} 342 int * q = p++; // expected-note{{used in pointer arithmetic here}} 343 int a[p[1]]; // expected-note{{used in buffer access here}} 344 int b = p[1]; // expected-note{{used in buffer access here}} 345 return p[1]; // expected-note{{used in buffer access here}} 346 } 347 348 template<typename T> void fArr(T t[], long long idx) { 349 // expected-warning@-1{{'t' is an unsafe pointer used for buffer access}} 350 foo(t[1]); // expected-note{{used in buffer access here}} 351 T ar[8]; // expected-warning{{'ar' is an unsafe buffer that does not perform bounds checks}} 352 // expected-note@-1{{change type of 'ar' to 'std::array' to label it for hardening}} 353 foo(ar[idx]); // expected-note{{used in buffer access here}} 354 } 355 356 template void fArr<int>(int t[], long long); // FIXME: expected note {{in instantiation of}} 357 358 int testReturn(int t[]) {// expected-note{{change type of 't' to 'std::span' to preserve bounds information}} 359 // expected-warning@-1{{'t' is an unsafe pointer used for buffer access}} 360 return t[1]; // expected-note{{used in buffer access here}} 361 } 362 363 int testArrayAccesses(int n, int idx) { 364 // auto deduced array type 365 int cArr[2][3] = {{1, 2, 3}, {4, 5, 6}}; 366 // expected-warning@-1{{'cArr' is an unsafe buffer that does not perform bounds checks}} 367 int d = cArr[0][0]; 368 foo(cArr[0][0]); 369 foo(cArr[idx][idx + 1]); // expected-note{{used in buffer access here}} 370 // expected-warning@-1{{unsafe buffer access}} 371 auto cPtr = cArr[idx][idx * 2]; // expected-note{{used in buffer access here}} 372 // expected-warning@-1{{unsafe buffer access}} 373 foo(cPtr); 374 375 // Typdefs 376 typedef int A[3]; 377 const A tArr = {4, 5, 6}; 378 foo(tArr[0], tArr[1]); 379 return cArr[0][1]; // expected-warning{{unsafe buffer access}} 380 } 381 382 void testArrayPtrArithmetic(int x[]) { // expected-warning{{'x' is an unsafe pointer used for buffer access}} 383 foo (x + 3); // expected-note{{used in pointer arithmetic here}} 384 385 int y[3] = {0, 1, 2}; // expected-warning{{'y' is an unsafe buffer that does not perform bounds checks}} 386 foo(y + 4); // expected-note{{used in pointer arithmetic here}} 387 } 388 389 void testMultiLineDeclStmt(int * p) { 390 int 391 392 * 393 394 ap1 = p; // expected-warning{{'ap1' is an unsafe pointer used for buffer access}} \ 395 expected-note{{change type of 'ap1' to 'std::span' to preserve bounds information}} 396 397 foo(ap1[1]); // expected-note{{used in buffer access here}} 398 } 399 400 #endif 401