xref: /llvm-project/clang/test/SemaCXX/warn-unsafe-buffer-usage.cpp (revision b2ac5fd724c44cf662caed84bd8f84af574b981d)
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   // Not to warn subscripts on arrays
53   foo(a[1], 1[a],
54       b[3][4],
55       4[b][3],
56       4[3[b]]);
57 
58   // Not to warn when index is zero
59   foo(p[0], pp[0][0], 0[0[pp]], 0[pp][0],
60       ((int*)voidPtrCall())[0],
61       0[(int*)voidPtrCall()],
62       charPtrCall()[0],
63       0[charPtrCall()]
64       );
65 }
66 
67 void testArraySubscriptsWithAuto(int *p, int **pp) {
68   int a[10];
69 
70   auto ap1 = a;
71 
72   foo(ap1[1]);  // expected-warning{{unchecked operation on raw buffer in expression}}
73 
74   auto ap2 = p;
75 
76   foo(ap2[1]);  // expected-warning{{unchecked operation on raw buffer in expression}}
77 
78   auto ap3 = pp;
79 
80   foo(ap3[1][1]); // expected-warning2{{unchecked operation on raw buffer in expression}}
81 
82   auto ap4 = *pp;
83 
84   foo(ap4[1]);  // expected-warning{{unchecked operation on raw buffer in expression}}
85 }
86 
87 void testUnevaluatedContext(int * p) {
88   //TODO: do not warn for unevaluated context
89   foo(sizeof(p[1]),             // expected-warning{{unchecked operation on raw buffer in expression}}
90       sizeof(decltype(p[1])));  // expected-warning{{unchecked operation on raw buffer in expression}}
91 }
92 
93 void testQualifiedParameters(const int * p, const int * const q,
94 			     const int a[10], const int b[10][10],
95 			     int (&c)[10]) {
96   foo(p[1], 1[p], p[-1],   // expected-warning3{{unchecked operation on raw buffer in expression}}
97       q[1], 1[q], q[-1],   // expected-warning3{{unchecked operation on raw buffer in expression}}
98       a[1],                // expected-warning{{unchecked operation on raw buffer in expression}}     `a` is of pointer type
99       b[1][2],             // expected-warning{{unchecked operation on raw buffer in expression}}     `b[1]` is of array type
100       c[1]                 // `c` is of array type
101       );
102 }
103 
104 struct T {
105   int a[10];
106   int * b;
107   struct {
108     int a[10];
109     int * b;
110   } c;
111 };
112 
113 typedef struct T T_t;
114 
115 T_t funRetT();
116 T_t * funRetTStar();
117 
118 void testStructMembers(struct T * sp, struct T s, T_t * sp2, T_t s2) {
119   foo(sp->a[1],
120       sp->b[1],     // expected-warning{{unchecked operation on raw buffer in expression}}
121       sp->c.a[1],
122       sp->c.b[1],   // expected-warning{{unchecked operation on raw buffer in expression}}
123       s.a[1],
124       s.b[1],       // expected-warning{{unchecked operation on raw buffer in expression}}
125       s.c.a[1],
126       s.c.b[1],     // expected-warning{{unchecked operation on raw buffer in expression}}
127       sp2->a[1],
128       sp2->b[1],    // expected-warning{{unchecked operation on raw buffer in expression}}
129       sp2->c.a[1],
130       sp2->c.b[1],  // expected-warning{{unchecked operation on raw buffer in expression}}
131       s2.a[1],
132       s2.b[1],      // expected-warning{{unchecked operation on raw buffer in expression}}
133       s2.c.a[1],
134       s2.c.b[1],           // expected-warning{{unchecked operation on raw buffer in expression}}
135       funRetT().a[1],
136       funRetT().b[1],      // expected-warning{{unchecked operation on raw buffer in expression}}
137       funRetTStar()->a[1],
138       funRetTStar()->b[1]  // expected-warning{{unchecked operation on raw buffer in expression}}
139       );
140 }
141 
142 int garray[10];
143 int * gp = garray;
144 int gvar = gp[1];  // FIXME: file scope unsafe buffer access is not warned
145 
146 void testLambdaCaptureAndGlobal(int * p) {
147   int a[10];
148 
149   auto Lam = [p, a]() {
150     return p[1] // expected-warning{{unchecked operation on raw buffer in expression}}
151       + a[1] + garray[1]
152       + gp[1];  // expected-warning{{unchecked operation on raw buffer in expression}}
153   };
154 }
155 
156 typedef T_t * T_ptr_t;
157 
158 void testTypedefs(T_ptr_t p) {
159   foo(p[1],      // expected-warning{{unchecked operation on raw buffer in expression}}
160       p[1].a[1], // expected-warning{{unchecked operation on raw buffer in expression}}
161       p[1].b[1]  // expected-warning2{{unchecked operation on raw buffer in expression}}
162       );
163 }
164 
165 template<typename T, int N> T f(T t, T * pt, T a[N], T (&b)[N]) {
166   foo(pt[1],    // expected-warning{{unchecked operation on raw buffer in expression}}
167       a[1],     // expected-warning{{unchecked operation on raw buffer in expression}}
168       b[1]);    // `b` is of array type
169   return &t[1]; // expected-warning{{unchecked operation on raw buffer in expression}}
170 }
171 
172 void testTemplate(int * p) {
173   int *a[10];
174   foo(f(p, &p, a, a)[1]); // expected-warning{{unchecked operation on raw buffer in expression}}, \
175                              expected-note{{in instantiation of function template specialization 'f<int *, 10>' requested here}}
176 }
177 
178 void testPointerToMember() {
179   struct S_t {
180     int x;
181     int * y;
182   } S;
183 
184   int S_t::* p = &S_t::x;
185   int * S_t::* q = &S_t::y;
186 
187   foo(S.*p,
188       (S.*q)[1]);  // expected-warning{{unchecked operation on raw buffer in expression}}
189 }
190 
191 // test that nested callable definitions are scanned only once
192 void testNestedCallableDefinition(int * p) {
193   class A {
194     void inner(int * p) {
195       p++; // expected-warning{{unchecked operation on raw buffer in expression}}
196     }
197 
198     static void innerStatic(int * p) {
199       p++; // expected-warning{{unchecked operation on raw buffer in expression}}
200     }
201 
202     void innerInner(int * p) {
203       auto Lam = [p]() {
204         int * q = p;
205         q++;   // expected-warning{{unchecked operation on raw buffer in expression}}
206         return *q;
207       };
208     }
209   };
210 
211   auto Lam = [p]() {
212     int * q = p;
213     q++;  // expected-warning{{unchecked operation on raw buffer in expression}}
214     return *q;
215   };
216 
217   auto LamLam = [p]() {
218     auto Lam = [p]() {
219       int * q = p;
220       q++;  // expected-warning{{unchecked operation on raw buffer in expression}}
221       return *q;
222     };
223   };
224 
225   void (^Blk)(int*) = ^(int *p) {
226     p++;   // expected-warning{{unchecked operation on raw buffer in expression}}
227   };
228 
229   void (^BlkBlk)(int*) = ^(int *p) {
230     void (^Blk)(int*) = ^(int *p) {
231       p++;   // expected-warning{{unchecked operation on raw buffer in expression}}
232     };
233     Blk(p);
234   };
235 
236   // lambda and block as call arguments...
237   foo( [p]() { int * q = p;
238               q++;  // expected-warning{{unchecked operation on raw buffer in expression}}
239               return *q;
240        },
241        ^(int *p) { p++;   // expected-warning{{unchecked operation on raw buffer in expression}}
242        }
243      );
244 }
245 
246 void testVariableDecls(int * p) {
247   int * q = p++;      // expected-warning{{unchecked operation on raw buffer in expression}}
248   int a[p[1]];        // expected-warning{{unchecked operation on raw buffer in expression}}
249   int b = p[1];       // expected-warning{{unchecked operation on raw buffer in expression}}
250 }
251 
252 #endif
253