410 lines · cpp
1// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage \2// RUN: -fsafe-buffer-usage-suggestions \3// RUN: -fblocks -include %s -verify %s4 5// RUN: %clang -x c++ -fsyntax-only -fblocks -include %s %s 2>&1 | FileCheck --allow-empty %s6// RUN: %clang_cc1 -std=c++11 -fblocks -include %s %s 2>&1 | FileCheck --allow-empty %s7// RUN: %clang_cc1 -std=c++20 -fblocks -include %s %s 2>&1 | FileCheck --allow-empty %s8// CHECK-NOT: [-Wunsafe-buffer-usage]9 10#ifndef INCLUDED11#define INCLUDED12#pragma clang system_header13 14// no spanification warnings for system headers15void foo(...); // let arguments of `foo` to hold testing expressions16void 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#else28 29void 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 36void * voidPtrCall(void);37char * charPtrCall(void);38 39void 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 zero77 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 85void 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 97void testUnevaluatedContext(int * p) {// no-warning98 foo(sizeof(p[1]), // no-warning99 sizeof(decltype(p[1]))); // no-warning100}101 102void 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 type111 b[1][2] // expected-note{{used in buffer access here}} `b[1]` is of array type112 );113}114 115struct T {116 int a[10];117 int * b;118 struct {119 int a[10];120 int * b;121 } c;122};123 124typedef struct T T_t;125 126T_t funRetT();127T_t * funRetTStar();128 129void testStructMembers(struct T * sp, struct T s, T_t * sp2, T_t s2) {130 foo(sp->a[1],131 sp->b[1], // expected-warning{{unsafe buffer access}}132 sp->c.a[1],133 sp->c.b[1], // expected-warning{{unsafe buffer access}}134 s.a[1],135 s.b[1], // expected-warning{{unsafe buffer access}}136 s.c.a[1],137 s.c.b[1], // expected-warning{{unsafe buffer access}}138 sp2->a[1],139 sp2->b[1], // expected-warning{{unsafe buffer access}}140 sp2->c.a[1],141 sp2->c.b[1], // expected-warning{{unsafe buffer access}}142 s2.a[1],143 s2.b[1], // expected-warning{{unsafe buffer access}}144 s2.c.a[1],145 s2.c.b[1], // expected-warning{{unsafe buffer access}}146 funRetT().a[1],147 funRetT().b[1], // expected-warning{{unsafe buffer access}}148 funRetTStar()->a[1],149 funRetTStar()->b[1] // expected-warning{{unsafe buffer access}}150 );151}152 153union Foo {154 bool b;155 int arr[10];156};157 158int testUnionMembers(Foo f) {159 int a = f.arr[0];160 a = f.arr[5];161 a = f.arr[10]; // expected-warning{{unsafe buffer access}}162 return a;163}164 165int garray[10]; // expected-warning{{'garray' is an unsafe buffer that does not perform bounds checks}}166int * gp = garray; // expected-warning{{'gp' is an unsafe pointer used for buffer access}}167int gvar = gp[1]; // FIXME: file scope unsafe buffer access is not warned168 169void 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](int idx) {174 return p[1] // expected-note{{used in buffer access here}}175 + a[idx] + garray[idx]// expected-note2{{used in buffer access here}}176 + gp[1]; // expected-note{{used in buffer access here}}177 178 };179}180 181auto 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 187void 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 // expected-note@-1{{change type of 'b' to 'std::array' to label it for hardening}}191 int c[10];192 193 auto Lam1 = [a](unsigned idx) {194 return a[idx]; // expected-note{{used in buffer access here}}195 };196 197 auto Lam2 = [x = b[c[5]]]() { // expected-note{{used in buffer access here}}198 return x;199 };200 201 auto Lam = [x = c](unsigned idx) { // expected-warning{{'x' is an unsafe pointer used for buffer access}}202 return x[idx]; // expected-note{{used in buffer access here}}203 };204}205 206void testLambdaImplicitCapture(long idx) {207 int a[10]; // expected-warning{{'a' is an unsafe buffer that does not perform bounds checks}}208 // expected-note@-1{{change type of 'a' to 'std::array' to label it for hardening}}209 int b[10]; // expected-warning{{'b' is an unsafe buffer that does not perform bounds checks}}210 // expected-note@-1{{change type of 'b' to 'std::array' to label it for hardening}}211 212 auto Lam1 = [=]() {213 return a[idx]; // expected-note{{used in buffer access here}}214 };215 216 auto Lam2 = [&]() {217 return b[idx]; // expected-note{{used in buffer access here}}218 };219}220 221typedef T_t * T_ptr_t;222 223void testTypedefs(T_ptr_t p) {224 // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}}225 foo(p[1], // expected-note{{used in buffer access here}}226 p[1].a[1], // expected-note{{used in buffer access here}}227 p[1].b[1] // expected-note{{used in buffer access here}}228 // expected-warning@-1{{unsafe buffer access}}229 );230}231 232template<typename T, int N> T f(T t, T * pt, T a[N], T (&b)[N]) {233 // expected-warning@-1{{'t' is an unsafe pointer used for buffer access}}234 // expected-warning@-2{{'pt' is an unsafe pointer used for buffer access}}235 // expected-warning@-3{{'a' is an unsafe pointer used for buffer access}}236 foo(pt[1], // expected-note{{used in buffer access here}}237 a[1], // expected-note{{used in buffer access here}}238 b[1]);239 return &t[1]; // expected-note{{used in buffer access here}}240}241 242// Testing pointer arithmetic for pointer-to-int, qualified multi-level243// pointer, pointer to a template type, and auto type244T_ptr_t getPtr();245 246template<typename T>247void testPointerArithmetic(int * p, const int **q, T * x) {248// expected-warning@-1{{'p' is an unsafe pointer used for buffer access}}249// expected-warning@-2{{'x' is an unsafe pointer used for buffer access}}250 int a[10];251 auto y = &a[0]; // expected-warning{{'y' is an unsafe pointer used for buffer access}}252 253 foo(p + 1, 1 + p, p - 1, // expected-note3{{used in pointer arithmetic here}}254 *q + 1, 1 + *q, *q - 1, // expected-warning3{{unsafe pointer arithmetic}}255 x + 1, 1 + x, x - 1, // expected-note3{{used in pointer arithmetic here}}256 y + 1, 1 + y, y - 1, // expected-note3{{used in pointer arithmetic here}}257 getPtr() + 1, 1 + getPtr(), getPtr() - 1 // expected-warning3{{unsafe pointer arithmetic}}258 );259 260 p += 1; p -= 1; // expected-note2{{used in pointer arithmetic here}}261 *q += 1; *q -= 1; // expected-warning2{{unsafe pointer arithmetic}}262 y += 1; y -= 1; // expected-note2{{used in pointer arithmetic here}}263 x += 1; x -= 1; // expected-note2{{used in pointer arithmetic here}}264}265 266void testTemplate(int * p) {267 int *a[10];268 foo(f(p, &p, a, a)[1]); // expected-warning{{unsafe buffer access}}269 // FIXME: expected note@-1{{in instantiation of function template specialization 'f<int *, 10>' requested here}}270 271 const int **q = const_cast<const int **>(&p);272 273 testPointerArithmetic(p, q, p); //FIXME: expected note{{in instantiation of}}274}275 276void testPointerToMember() {277 struct S_t {278 int x;279 int * y;280 } S;281 282 int S_t::* p = &S_t::x;283 int * S_t::* q = &S_t::y;284 285 foo(S.*p,286 (S.*q)[1]); // expected-warning{{unsafe buffer access}}287}288 289// test that nested callable definitions are scanned only once290void testNestedCallableDefinition(int * p) {291 class A {292 void inner(int * p) {293 // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}}294 p++; // expected-note{{used in pointer arithmetic here}}295 }296 297 static void innerStatic(int * p) {298 // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}}299 p++; // expected-note{{used in pointer arithmetic here}}300 }301 302 void innerInner(int * p) {303 auto Lam = [p]() {304 int * q = p; // expected-warning{{'q' is an unsafe pointer used for buffer access}}305 q++; // expected-note{{used in pointer arithmetic here}}306 return *q;307 };308 }309 };310 311 auto Lam = [p]() {312 int * q = p; // expected-warning{{'q' is an unsafe pointer used for buffer access}}313 q++; // expected-note{{used in pointer arithmetic here}}314 return *q;315 };316 317 auto LamLam = [p]() {318 auto Lam = [p]() {319 int * q = p; // expected-warning{{'q' is an unsafe pointer used for buffer access}}320 q++; // expected-note{{used in pointer arithmetic here}}321 return *q;322 };323 };324 325 void (^Blk)(int*) = ^(int *p) {326 // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}}327 p++; // expected-note{{used in pointer arithmetic here}}328 };329 330 void (^BlkBlk)(int*) = ^(int *p) {331 void (^Blk)(int*) = ^(int *p) {332 // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}}333 p++; // expected-note{{used in pointer arithmetic here}}334 };335 Blk(p);336 };337 338 // lambda and block as call arguments...339 foo( [p]() { int * q = p; // expected-warning{{'q' is an unsafe pointer used for buffer access}}340 q++; // expected-note{{used in pointer arithmetic here}}341 return *q;342 },343 ^(int *p) { // expected-warning{{'p' is an unsafe pointer used for buffer access}}344 p++; // expected-note{{used in pointer arithmetic here}}345 }346 );347}348 349int testVariableDecls(int * p) {350 // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}}351 int * q = p++; // expected-note{{used in pointer arithmetic here}}352 int a[p[1]]; // expected-note{{used in buffer access here}}353 int b = p[1]; // expected-note{{used in buffer access here}}354 return p[1]; // expected-note{{used in buffer access here}}355}356 357template<typename T> void fArr(T t[], long long idx) {358 // expected-warning@-1{{'t' is an unsafe pointer used for buffer access}}359 foo(t[1]); // expected-note{{used in buffer access here}}360 T ar[8]; // expected-warning{{'ar' is an unsafe buffer that does not perform bounds checks}}361 // expected-note@-1{{change type of 'ar' to 'std::array' to label it for hardening}}362 foo(ar[idx]); // expected-note{{used in buffer access here}}363}364 365template void fArr<int>(int t[], long long); // FIXME: expected note {{in instantiation of}}366 367int testReturn(int t[]) {// expected-note{{change type of 't' to 'std::span' to preserve bounds information}}368 // expected-warning@-1{{'t' is an unsafe pointer used for buffer access}}369 return t[1]; // expected-note{{used in buffer access here}}370}371 372int testArrayAccesses(int n, int idx) {373 // auto deduced array type374 int cArr[2][3] = {{1, 2, 3}, {4, 5, 6}};375 // expected-warning@-1{{'cArr' is an unsafe buffer that does not perform bounds checks}}376 int d = cArr[0][0];377 foo(cArr[0][0]);378 foo(cArr[idx][idx + 1]); // expected-note{{used in buffer access here}}379 // expected-warning@-1{{unsafe buffer access}}380 auto cPtr = cArr[idx][idx * 2]; // expected-note{{used in buffer access here}}381 // expected-warning@-1{{unsafe buffer access}}382 foo(cPtr);383 384 // Typdefs385 typedef int A[3];386 const A tArr = {4, 5, 6};387 foo(tArr[0], tArr[1]);388 return cArr[0][1];389}390 391void testArrayPtrArithmetic(int x[]) { // expected-warning{{'x' is an unsafe pointer used for buffer access}}392 foo (x + 3); // expected-note{{used in pointer arithmetic here}}393 394 int y[3] = {0, 1, 2}; // expected-warning{{'y' is an unsafe buffer that does not perform bounds checks}}395 foo(y + 4); // expected-note{{used in pointer arithmetic here}}396}397 398void testMultiLineDeclStmt(int * p) {399 int400 401 *402 403 ap1 = p; // expected-warning{{'ap1' is an unsafe pointer used for buffer access}} \404 expected-note{{change type of 'ap1' to 'std::span' to preserve bounds information}}405 406 foo(ap1[1]); // expected-note{{used in buffer access here}}407}408 409#endif410