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