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