xref: /llvm-project/clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp (revision 1e270be0886c3a770e7a967679552a02dfc1dca9)
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 // FIXME: Add test for lambda capture with initializer. E. g. auto Lam = [new_p = p]() {...
170 void testLambdaCaptureAndGlobal(int * p) {
171   // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}}
172   int a[10];              // expected-warning{{'a' is an unsafe buffer that does not perform bounds checks}}
173 
174   auto Lam = [p, a]() {
175     return p[1]           // expected-note{{used in buffer access here}}
176       + a[1] + garray[1]  // expected-note2{{used in buffer access here}}
177       + gp[1];            // expected-note{{used in buffer access here}}
178   };
179 }
180 
181 typedef T_t * T_ptr_t;
182 
183 void testTypedefs(T_ptr_t p) {
184   // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}}
185   foo(p[1],       // expected-note{{used in buffer access here}}
186       p[1].a[1],  // expected-note{{used in buffer access here}}
187                   // expected-warning@-1{{unsafe buffer access}}
188       p[1].b[1]   // expected-note{{used in buffer access here}}
189                   // expected-warning@-1{{unsafe buffer access}}
190       );
191 }
192 
193 template<typename T, int N> T f(T t, T * pt, T a[N], T (&b)[N]) {
194   // expected-warning@-1{{'t' is an unsafe pointer used for buffer access}}
195   // expected-warning@-2{{'pt' is an unsafe pointer used for buffer access}}
196   // expected-warning@-3{{'a' is an unsafe pointer used for buffer access}}
197   // expected-warning@-4{{'b' is an unsafe buffer that does not perform bounds checks}}
198   foo(pt[1],    // expected-note{{used in buffer access here}}
199       a[1],     // expected-note{{used in buffer access here}}
200       b[1]);    // expected-note{{used in buffer access here}}
201   return &t[1]; // expected-note{{used in buffer access here}}
202 }
203 
204 // Testing pointer arithmetic for pointer-to-int, qualified multi-level
205 // pointer, pointer to a template type, and auto type
206 T_ptr_t getPtr();
207 
208 template<typename T>
209 void testPointerArithmetic(int * p, const int **q, T * x) {
210 // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}}
211 // expected-warning@-2{{'x' is an unsafe pointer used for buffer access}}
212   int a[10];
213   auto y = &a[0]; // expected-warning{{'y' is an unsafe pointer used for buffer access}}
214 
215   foo(p + 1, 1 + p, p - 1,      // expected-note3{{used in pointer arithmetic here}}
216       *q + 1, 1 + *q, *q - 1,   // expected-warning3{{unsafe pointer arithmetic}}
217       x + 1, 1 + x, x - 1,      // expected-note3{{used in pointer arithmetic here}}
218       y + 1, 1 + y, y - 1,      // expected-note3{{used in pointer arithmetic here}}
219       getPtr() + 1, 1 + getPtr(), getPtr() - 1 // expected-warning3{{unsafe pointer arithmetic}}
220       );
221 
222   p += 1;  p -= 1;  // expected-note2{{used in pointer arithmetic here}}
223   *q += 1; *q -= 1; // expected-warning2{{unsafe pointer arithmetic}}
224   y += 1; y -= 1;   // expected-note2{{used in pointer arithmetic here}}
225   x += 1; x -= 1;   // expected-note2{{used in pointer arithmetic here}}
226 }
227 
228 void testTemplate(int * p) {
229   int *a[10];
230   foo(f(p, &p, a, a)[1]); // expected-warning{{unsafe buffer access}}
231                           // FIXME: expected note@-1{{in instantiation of function template specialization 'f<int *, 10>' requested here}}
232 
233   const int **q = const_cast<const int **>(&p);
234 
235   testPointerArithmetic(p, q, p); //FIXME: expected note{{in instantiation of}}
236 }
237 
238 void testPointerToMember() {
239   struct S_t {
240     int x;
241     int * y;
242   } S;
243 
244   int S_t::* p = &S_t::x;
245   int * S_t::* q = &S_t::y;
246 
247   foo(S.*p,
248       (S.*q)[1]);  // expected-warning{{unsafe buffer access}}
249 }
250 
251 // test that nested callable definitions are scanned only once
252 void testNestedCallableDefinition(int * p) {
253   class A {
254     void inner(int * p) {
255       // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}}
256       p++; // expected-note{{used in pointer arithmetic here}}
257     }
258 
259     static void innerStatic(int * p) {
260       // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}}
261       p++; // expected-note{{used in pointer arithmetic here}}
262     }
263 
264     void innerInner(int * p) {
265       auto Lam = [p]() {
266         int * q = p;    // expected-warning{{'q' is an unsafe pointer used for buffer access}}
267         q++;            // expected-note{{used in pointer arithmetic here}}
268         return *q;
269       };
270     }
271   };
272 
273   auto Lam = [p]() {
274     int * q = p;  // expected-warning{{'q' is an unsafe pointer used for buffer access}}
275     q++;          // expected-note{{used in pointer arithmetic here}}
276     return *q;
277   };
278 
279   auto LamLam = [p]() {
280     auto Lam = [p]() {
281       int * q = p;  // expected-warning{{'q' is an unsafe pointer used for buffer access}}
282       q++;          // expected-note{{used in pointer arithmetic here}}
283       return *q;
284     };
285   };
286 
287   void (^Blk)(int*) = ^(int *p) {
288     // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}}
289     p++;   // expected-note{{used in pointer arithmetic here}}
290   };
291 
292   void (^BlkBlk)(int*) = ^(int *p) {
293     void (^Blk)(int*) = ^(int *p) {
294       // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}}
295       p++;   // expected-note{{used in pointer arithmetic here}}
296     };
297     Blk(p);
298   };
299 
300   // lambda and block as call arguments...
301   foo( [p]() { int * q = p; // expected-warning{{'q' is an unsafe pointer used for buffer access}}
302               q++;          // expected-note{{used in pointer arithmetic here}}
303               return *q;
304        },
305        ^(int *p) {  // expected-warning{{'p' is an unsafe pointer used for buffer access}}
306         p++;        // expected-note{{used in pointer arithmetic here}}
307        }
308      );
309 }
310 
311 int testVariableDecls(int * p) {
312   // expected-warning@-1{{'p' is an unsafe pointer used for buffer access}}
313   int * q = p++;      // expected-note{{used in pointer arithmetic here}}
314   int a[p[1]];        // expected-note{{used in buffer access here}}
315   int b = p[1];       // expected-note{{used in buffer access here}}
316   return p[1];        // expected-note{{used in buffer access here}}
317 }
318 
319 template<typename T> void fArr(T t[]) {
320   // expected-warning@-1{{'t' is an unsafe pointer used for buffer access}}
321   foo(t[1]);    // expected-note{{used in buffer access here}}
322   T ar[8];      // expected-warning{{'ar' is an unsafe buffer that does not perform bounds checks}}
323   foo(ar[5]);   // expected-note{{used in buffer access here}}
324 }
325 
326 template void fArr<int>(int t[]); // FIXME: expected note {{in instantiation of}}
327 
328 int testReturn(int t[]) {// expected-note{{change type of 't' to 'std::span' to preserve bounds information}}
329   // expected-warning@-1{{'t' is an unsafe pointer used for buffer access}}
330   return t[1]; // expected-note{{used in buffer access here}}
331 }
332 
333 int testArrayAccesses(int n) {
334     // auto deduced array type
335     int cArr[2][3] = {{1, 2, 3}, {4, 5, 6}};
336     // expected-warning@-1{{'cArr' is an unsafe buffer that does not perform bounds checks}}
337     int d = cArr[0][0];
338     foo(cArr[0][0]);
339     foo(cArr[1][2]);        // expected-note{{used in buffer access here}}
340                             // expected-warning@-1{{unsafe buffer access}}
341     auto cPtr = cArr[1][2]; // expected-note{{used in buffer access here}}
342                             // expected-warning@-1{{unsafe buffer access}}
343     foo(cPtr);
344 
345     // Typdefs
346     typedef int A[3];
347     const A tArr = {4, 5, 6};
348     // expected-warning@-1{{'tArr' is an unsafe buffer that does not perform bounds checks}}
349     foo(tArr[0], tArr[1]);  // expected-note{{used in buffer access here}}
350     return cArr[0][1];      // expected-warning{{unsafe buffer access}}
351 }
352 
353 void testArrayPtrArithmetic(int x[]) { // expected-warning{{'x' is an unsafe pointer used for buffer access}}
354   foo (x + 3); // expected-note{{used in pointer arithmetic here}}
355 
356   int y[3] = {0, 1, 2}; // expected-warning{{'y' is an unsafe buffer that does not perform bounds checks}}
357   foo(y + 4); // expected-note{{used in pointer arithmetic here}}
358 }
359 
360 void testMultiLineDeclStmt(int * p) {
361   auto
362 
363 
364   ap1 = p;      // expected-warning{{'ap1' is an unsafe pointer used for buffer access}} \
365          	   expected-note{{change type of 'ap1' to 'std::span' to preserve bounds information}}
366 
367   foo(ap1[1]);  // expected-note{{used in buffer access here}}
368 }
369 
370 #endif
371