xref: /llvm-project/clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp (revision a29e67614c3b7018287e5f68c57bba7618aa880e)
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