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 *p, int **pp) { // expected-note{{change type of 'pp' to 'std::span' to preserve bounds information}} 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 int b[10][10]; // expected-warning{{'b' is an unsafe buffer that does not perform bounds checks}} 65 66 foo(a[1], 1[a], // expected-note2{{used in buffer access here}} 67 b[3][4], // expected-warning{{unsafe buffer access}} 68 // expected-note@-1{{used in buffer access here}} 69 4[b][3], // expected-warning{{unsafe buffer access}} 70 // expected-note@-1{{used in buffer access here}} 71 4[3[b]]); // expected-warning{{unsafe buffer access}} 72 // expected-note@-1{{used in buffer access here}} 73 74 // Not to warn when index is zero 75 foo(p[0], pp[0][0], 0[0[pp]], 0[pp][0], 76 ((int*)voidPtrCall())[0], 77 0[(int*)voidPtrCall()], 78 charPtrCall()[0], 79 0[charPtrCall()] 80 ); 81 } 82 83 void testArraySubscriptsWithAuto(int *p, int **pp) { 84 int a[10]; 85 auto ap1 = a; // expected-warning{{'ap1' is an unsafe pointer used for buffer access}} \ 86 expected-note{{change type of 'ap1' to 'std::span' to preserve bounds information}} 87 88 foo(ap1[1]); // expected-note{{used in buffer access here}} 89 90 auto ap2 = p; // expected-warning{{'ap2' is an unsafe pointer used for buffer access}} \ 91 expected-note{{change type of 'ap2' to 'std::span' to preserve bounds information}} 92 93 foo(ap2[1]); // expected-note{{used in buffer access here}} 94 95 auto ap3 = pp; // expected-warning{{'ap3' is an unsafe pointer used for buffer access}} \ 96 expected-note{{change type of 'ap3' to 'std::span' to preserve bounds information}} 97 98 foo(ap3[1][1]); // expected-note{{used in buffer access here}} 99 // expected-warning@-1{{unsafe buffer access}} 100 101 auto ap4 = *pp; // expected-warning{{'ap4' is an unsafe pointer used for buffer access}} \ 102 expected-note{{change type of 'ap4' to 'std::span' to preserve bounds information}} 103 104 foo(ap4[1]); // expected-note{{used in buffer access here}} 105 } 106 107 void testUnevaluatedContext(int * p) {// no-warning 108 foo(sizeof(p[1]), // no-warning 109 sizeof(decltype(p[1]))); // no-warning 110 } 111 112 // expected-note@+1{{change type of 'a' to 'std::span' to preserve bounds information}} 113 void testQualifiedParameters(const int * p, const int * const q, const int a[10], const int b[10][10]) { 114 // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} 115 // expected-warning@-2{{'q' is an unsafe pointer used for buffer access}} 116 // expected-warning@-3{{'a' is an unsafe pointer used for buffer access}} 117 // expected-warning@-4{{'b' is an unsafe pointer used for buffer access}} 118 119 foo(p[1], 1[p], p[-1], // expected-note3{{used in buffer access here}} 120 q[1], 1[q], q[-1], // expected-note3{{used in buffer access here}} 121 a[1], // expected-note{{used in buffer access here}} `a` is of pointer type 122 b[1][2] // expected-note{{used in buffer access here}} `b[1]` is of array type 123 // expected-warning@-1{{unsafe buffer access}} 124 ); 125 } 126 127 struct T { 128 int a[10]; 129 int * b; 130 struct { 131 int a[10]; 132 int * b; 133 } c; 134 }; 135 136 typedef struct T T_t; 137 138 T_t funRetT(); 139 T_t * funRetTStar(); 140 141 void testStructMembers(struct T * sp, struct T s, T_t * sp2, T_t s2) { 142 foo(sp->a[1], // expected-warning{{unsafe buffer access}} 143 sp->b[1], // expected-warning{{unsafe buffer access}} 144 sp->c.a[1], // expected-warning{{unsafe buffer access}} 145 sp->c.b[1], // expected-warning{{unsafe buffer access}} 146 s.a[1], // expected-warning{{unsafe buffer access}} 147 s.b[1], // expected-warning{{unsafe buffer access}} 148 s.c.a[1], // expected-warning{{unsafe buffer access}} 149 s.c.b[1], // expected-warning{{unsafe buffer access}} 150 sp2->a[1], // expected-warning{{unsafe buffer access}} 151 sp2->b[1], // expected-warning{{unsafe buffer access}} 152 sp2->c.a[1], // expected-warning{{unsafe buffer access}} 153 sp2->c.b[1], // expected-warning{{unsafe buffer access}} 154 s2.a[1], // expected-warning{{unsafe buffer access}} 155 s2.b[1], // expected-warning{{unsafe buffer access}} 156 s2.c.a[1], // expected-warning{{unsafe buffer access}} 157 s2.c.b[1], // expected-warning{{unsafe buffer access}} 158 funRetT().a[1], // expected-warning{{unsafe buffer access}} 159 funRetT().b[1], // expected-warning{{unsafe buffer access}} 160 funRetTStar()->a[1], // expected-warning{{unsafe buffer access}} 161 funRetTStar()->b[1] // expected-warning{{unsafe buffer access}} 162 ); 163 } 164 165 int garray[10]; // expected-warning{{'garray' is an unsafe buffer that does not perform bounds checks}} 166 int * gp = garray; // expected-warning{{'gp' is an unsafe pointer used for buffer access}} 167 int gvar = gp[1]; // FIXME: file scope unsafe buffer access is not warned 168 169 void testLambdaCaptureAndGlobal(int * p) { 170 // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} 171 int a[10]; // expected-warning{{'a' is an unsafe buffer that does not perform bounds checks}} 172 173 auto Lam = [p, a]() { 174 return p[1] // expected-note{{used in buffer access here}} 175 + a[1] + garray[1] // expected-note2{{used in buffer access here}} 176 + gp[1]; // expected-note{{used in buffer access here}} 177 178 }; 179 } 180 181 auto file_scope_lambda = [](int *ptr) { 182 // expected-warning@-1{{'ptr' is an unsafe pointer used for buffer access}} 183 184 ptr[5] = 10; // expected-note{{used in buffer access here}} 185 }; 186 187 void testLambdaCapture() { 188 int a[10]; // expected-warning{{'a' is an unsafe buffer that does not perform bounds checks}} 189 int b[10]; // expected-warning{{'b' is an unsafe buffer that does not perform bounds checks}} 190 int c[10]; 191 192 auto Lam1 = [a]() { 193 return a[1]; // expected-note{{used in buffer access here}} 194 }; 195 196 auto Lam2 = [x = b[3]]() { // expected-note{{used in buffer access here}} 197 return x; 198 }; 199 200 auto Lam = [x = c]() { // expected-warning{{'x' is an unsafe pointer used for buffer access}} 201 return x[3]; // expected-note{{used in buffer access here}} 202 }; 203 } 204 205 void testLambdaImplicitCapture() { 206 int a[10]; // expected-warning{{'a' is an unsafe buffer that does not perform bounds checks}} 207 int b[10]; // expected-warning{{'b' is an unsafe buffer that does not perform bounds checks}} 208 209 auto Lam1 = [=]() { 210 return a[1]; // expected-note{{used in buffer access here}} 211 }; 212 213 auto Lam2 = [&]() { 214 return b[1]; // expected-note{{used in buffer access here}} 215 }; 216 } 217 218 typedef T_t * T_ptr_t; 219 220 void testTypedefs(T_ptr_t p) { 221 // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} 222 foo(p[1], // expected-note{{used in buffer access here}} 223 p[1].a[1], // expected-note{{used in buffer access here}} 224 // expected-warning@-1{{unsafe buffer access}} 225 p[1].b[1] // expected-note{{used in buffer access here}} 226 // expected-warning@-1{{unsafe buffer access}} 227 ); 228 } 229 230 template<typename T, int N> T f(T t, T * pt, T a[N], T (&b)[N]) { 231 // expected-warning@-1{{'t' is an unsafe pointer used for buffer access}} 232 // expected-warning@-2{{'pt' is an unsafe pointer used for buffer access}} 233 // expected-warning@-3{{'a' is an unsafe pointer used for buffer access}} 234 // expected-warning@-4{{'b' is an unsafe buffer that does not perform bounds checks}} 235 foo(pt[1], // expected-note{{used in buffer access here}} 236 a[1], // expected-note{{used in buffer access here}} 237 b[1]); // expected-note{{used in buffer access here}} 238 return &t[1]; // expected-note{{used in buffer access here}} 239 } 240 241 // Testing pointer arithmetic for pointer-to-int, qualified multi-level 242 // pointer, pointer to a template type, and auto type 243 T_ptr_t getPtr(); 244 245 template<typename T> 246 void testPointerArithmetic(int * p, const int **q, T * x) { 247 // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} 248 // expected-warning@-2{{'x' is an unsafe pointer used for buffer access}} 249 int a[10]; 250 auto y = &a[0]; // expected-warning{{'y' is an unsafe pointer used for buffer access}} 251 252 foo(p + 1, 1 + p, p - 1, // expected-note3{{used in pointer arithmetic here}} 253 *q + 1, 1 + *q, *q - 1, // expected-warning3{{unsafe pointer arithmetic}} 254 x + 1, 1 + x, x - 1, // expected-note3{{used in pointer arithmetic here}} 255 y + 1, 1 + y, y - 1, // expected-note3{{used in pointer arithmetic here}} 256 getPtr() + 1, 1 + getPtr(), getPtr() - 1 // expected-warning3{{unsafe pointer arithmetic}} 257 ); 258 259 p += 1; p -= 1; // expected-note2{{used in pointer arithmetic here}} 260 *q += 1; *q -= 1; // expected-warning2{{unsafe pointer arithmetic}} 261 y += 1; y -= 1; // expected-note2{{used in pointer arithmetic here}} 262 x += 1; x -= 1; // expected-note2{{used in pointer arithmetic here}} 263 } 264 265 void testTemplate(int * p) { 266 int *a[10]; 267 foo(f(p, &p, a, a)[1]); // expected-warning{{unsafe buffer access}} 268 // FIXME: expected note@-1{{in instantiation of function template specialization 'f<int *, 10>' requested here}} 269 270 const int **q = const_cast<const int **>(&p); 271 272 testPointerArithmetic(p, q, p); //FIXME: expected note{{in instantiation of}} 273 } 274 275 void testPointerToMember() { 276 struct S_t { 277 int x; 278 int * y; 279 } S; 280 281 int S_t::* p = &S_t::x; 282 int * S_t::* q = &S_t::y; 283 284 foo(S.*p, 285 (S.*q)[1]); // expected-warning{{unsafe buffer access}} 286 } 287 288 // test that nested callable definitions are scanned only once 289 void testNestedCallableDefinition(int * p) { 290 class A { 291 void inner(int * p) { 292 // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} 293 p++; // expected-note{{used in pointer arithmetic here}} 294 } 295 296 static void innerStatic(int * p) { 297 // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} 298 p++; // expected-note{{used in pointer arithmetic here}} 299 } 300 301 void innerInner(int * p) { 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 }; 309 310 auto Lam = [p]() { 311 int * q = p; // expected-warning{{'q' is an unsafe pointer used for buffer access}} 312 q++; // expected-note{{used in pointer arithmetic here}} 313 return *q; 314 }; 315 316 auto LamLam = [p]() { 317 auto Lam = [p]() { 318 int * q = p; // expected-warning{{'q' is an unsafe pointer used for buffer access}} 319 q++; // expected-note{{used in pointer arithmetic here}} 320 return *q; 321 }; 322 }; 323 324 void (^Blk)(int*) = ^(int *p) { 325 // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} 326 p++; // expected-note{{used in pointer arithmetic here}} 327 }; 328 329 void (^BlkBlk)(int*) = ^(int *p) { 330 void (^Blk)(int*) = ^(int *p) { 331 // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} 332 p++; // expected-note{{used in pointer arithmetic here}} 333 }; 334 Blk(p); 335 }; 336 337 // lambda and block as call arguments... 338 foo( [p]() { int * q = p; // expected-warning{{'q' is an unsafe pointer used for buffer access}} 339 q++; // expected-note{{used in pointer arithmetic here}} 340 return *q; 341 }, 342 ^(int *p) { // expected-warning{{'p' is an unsafe pointer used for buffer access}} 343 p++; // expected-note{{used in pointer arithmetic here}} 344 } 345 ); 346 } 347 348 int testVariableDecls(int * p) { 349 // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}} 350 int * q = p++; // expected-note{{used in pointer arithmetic here}} 351 int a[p[1]]; // expected-note{{used in buffer access here}} 352 int b = p[1]; // expected-note{{used in buffer access here}} 353 return p[1]; // expected-note{{used in buffer access here}} 354 } 355 356 template<typename T> void fArr(T t[]) { 357 // expected-warning@-1{{'t' is an unsafe pointer used for buffer access}} 358 foo(t[1]); // expected-note{{used in buffer access here}} 359 T ar[8]; // expected-warning{{'ar' is an unsafe buffer that does not perform bounds checks}} 360 foo(ar[5]); // expected-note{{used in buffer access here}} 361 } 362 363 template void fArr<int>(int t[]); // FIXME: expected note {{in instantiation of}} 364 365 int testReturn(int t[]) {// expected-note{{change type of 't' to 'std::span' to preserve bounds information}} 366 // expected-warning@-1{{'t' is an unsafe pointer used for buffer access}} 367 return t[1]; // expected-note{{used in buffer access here}} 368 } 369 370 int testArrayAccesses(int n) { 371 // auto deduced array type 372 int cArr[2][3] = {{1, 2, 3}, {4, 5, 6}}; 373 // expected-warning@-1{{'cArr' is an unsafe buffer that does not perform bounds checks}} 374 int d = cArr[0][0]; 375 foo(cArr[0][0]); 376 foo(cArr[1][2]); // expected-note{{used in buffer access here}} 377 // expected-warning@-1{{unsafe buffer access}} 378 auto cPtr = cArr[1][2]; // expected-note{{used in buffer access here}} 379 // expected-warning@-1{{unsafe buffer access}} 380 foo(cPtr); 381 382 // Typdefs 383 typedef int A[3]; 384 const A tArr = {4, 5, 6}; 385 // expected-warning@-1{{'tArr' is an unsafe buffer that does not perform bounds checks}} 386 foo(tArr[0], tArr[1]); // expected-note{{used in buffer access here}} 387 return cArr[0][1]; // expected-warning{{unsafe buffer access}} 388 } 389 390 void testArrayPtrArithmetic(int x[]) { // expected-warning{{'x' is an unsafe pointer used for buffer access}} 391 foo (x + 3); // expected-note{{used in pointer arithmetic here}} 392 393 int y[3] = {0, 1, 2}; // expected-warning{{'y' is an unsafe buffer that does not perform bounds checks}} 394 foo(y + 4); // expected-note{{used in pointer arithmetic here}} 395 } 396 397 void testMultiLineDeclStmt(int * p) { 398 auto 399 400 401 ap1 = p; // expected-warning{{'ap1' is an unsafe pointer used for buffer access}} \ 402 expected-note{{change type of 'ap1' to 'std::span' to preserve bounds information}} 403 404 foo(ap1[1]); // expected-note{{used in buffer access here}} 405 } 406 407 #endif 408