xref: /llvm-project/clang/test/Analysis/std-c-library-functions-arg-constraints.c (revision da0660691f74b0350dee8e15f4ac942457e397e4)
1 // Check the basic reporting/warning and the application of constraints.
2 // RUN: %clang_analyze_cc1 %s \
3 // RUN:   -analyzer-checker=core \
4 // RUN:   -analyzer-checker=apiModeling.StdCLibraryFunctions \
5 // RUN:   -analyzer-checker=alpha.unix.StdCLibraryFunctionArgs \
6 // RUN:   -analyzer-checker=debug.StdCLibraryFunctionsTester \
7 // RUN:   -analyzer-checker=debug.ExprInspection \
8 // RUN:   -triple x86_64-unknown-linux-gnu \
9 // RUN:   -verify=report
10 
11 // Check the bugpath related to the reports.
12 // RUN: %clang_analyze_cc1 %s \
13 // RUN:   -analyzer-checker=core \
14 // RUN:   -analyzer-checker=apiModeling.StdCLibraryFunctions \
15 // RUN:   -analyzer-checker=alpha.unix.StdCLibraryFunctionArgs \
16 // RUN:   -analyzer-checker=debug.StdCLibraryFunctionsTester \
17 // RUN:   -analyzer-checker=debug.ExprInspection \
18 // RUN:   -triple x86_64-unknown-linux-gnu \
19 // RUN:   -analyzer-output=text \
20 // RUN:   -verify=bugpath
21 
22 void clang_analyzer_eval(int);
23 void clang_analyzer_warnIfReached();
24 
25 int glob;
26 
27 #define EOF -1
28 
29 int isalnum(int);
30 
31 void test_alnum_concrete(int v) {
32   int ret = isalnum(256); // \
33   // report-warning{{Function argument constraint is not satisfied}} \
34   // report-note{{}} \
35   // bugpath-warning{{Function argument constraint is not satisfied}} \
36   // bugpath-note{{}} \
37   // bugpath-note{{Function argument constraint is not satisfied}}
38   (void)ret;
39 }
40 
41 void test_alnum_symbolic(int x) {
42   int ret = isalnum(x); // \
43   // bugpath-note{{Assuming the character is non-alphanumeric}}
44   (void)ret;
45 
46   clang_analyzer_eval(EOF <= x && x <= 255); // \
47   // report-warning{{TRUE}} \
48   // bugpath-warning{{TRUE}} \
49   // bugpath-note{{TRUE}} \
50   // bugpath-note{{Left side of '&&' is true}} \
51   // bugpath-note{{'x' is <= 255}}
52 }
53 
54 void test_alnum_symbolic2(int x) {
55   if (x > 255) { // \
56     // bugpath-note{{Assuming 'x' is > 255}} \
57     // bugpath-note{{Taking true branch}}
58 
59     int ret = isalnum(x); // \
60     // report-warning{{Function argument constraint is not satisfied}} \
61     // report-note{{}} \
62     // bugpath-warning{{Function argument constraint is not satisfied}} \
63     // bugpath-note{{}} \
64     // bugpath-note{{Function argument constraint is not satisfied}}
65 
66     (void)ret;
67   }
68 }
69 
70 int toupper(int);
71 
72 void test_toupper_concrete(int v) {
73   int ret = toupper(256); // \
74   // report-warning{{Function argument constraint is not satisfied}} \
75   // report-note{{}} \
76   // bugpath-warning{{Function argument constraint is not satisfied}} \
77   // bugpath-note{{}} \
78   // bugpath-note{{Function argument constraint is not satisfied}}
79   (void)ret;
80 }
81 
82 void test_toupper_symbolic(int x) {
83   int ret = toupper(x);
84   (void)ret;
85 
86   clang_analyzer_eval(EOF <= x && x <= 255); // \
87   // report-warning{{TRUE}} \
88   // bugpath-warning{{TRUE}} \
89   // bugpath-note{{TRUE}} \
90   // bugpath-note{{Left side of '&&' is true}} \
91   // bugpath-note{{'x' is <= 255}}
92 }
93 
94 void test_toupper_symbolic2(int x) {
95   if (x > 255) { // \
96     // bugpath-note{{Assuming 'x' is > 255}} \
97     // bugpath-note{{Taking true branch}}
98 
99     int ret = toupper(x); // \
100     // report-warning{{Function argument constraint is not satisfied}} \
101     // report-note{{}} \
102     // bugpath-warning{{Function argument constraint is not satisfied}} \
103     // bugpath-note{{}} \
104     // bugpath-note{{Function argument constraint is not satisfied}}
105 
106     (void)ret;
107   }
108 }
109 
110 int tolower(int);
111 
112 void test_tolower_concrete(int v) {
113   int ret = tolower(256); // \
114   // report-warning{{Function argument constraint is not satisfied}} \
115   // report-note{{}} \
116   // bugpath-warning{{Function argument constraint is not satisfied}} \
117   // bugpath-note{{}} \
118   // bugpath-note{{Function argument constraint is not satisfied}}
119   (void)ret;
120 }
121 
122 void test_tolower_symbolic(int x) {
123   int ret = tolower(x);
124   (void)ret;
125 
126   clang_analyzer_eval(EOF <= x && x <= 255); // \
127   // report-warning{{TRUE}} \
128   // bugpath-warning{{TRUE}} \
129   // bugpath-note{{TRUE}} \
130   // bugpath-note{{Left side of '&&' is true}} \
131   // bugpath-note{{'x' is <= 255}}
132 }
133 
134 void test_tolower_symbolic2(int x) {
135   if (x > 255) { // \
136     // bugpath-note{{Assuming 'x' is > 255}} \
137     // bugpath-note{{Taking true branch}}
138 
139     int ret = tolower(x); // \
140     // report-warning{{Function argument constraint is not satisfied}} \
141     // report-note{{}} \
142     // bugpath-warning{{Function argument constraint is not satisfied}} \
143     // bugpath-note{{}} \
144     // bugpath-note{{Function argument constraint is not satisfied}}
145 
146     (void)ret;
147   }
148 }
149 
150 int toascii(int);
151 
152 void test_toascii_concrete(int v) {
153   int ret = toascii(256); // \
154   // report-warning{{Function argument constraint is not satisfied}} \
155   // report-note{{}} \
156   // bugpath-warning{{Function argument constraint is not satisfied}} \
157   // bugpath-note{{}} \
158   // bugpath-note{{Function argument constraint is not satisfied}}
159   (void)ret;
160 }
161 
162 void test_toascii_symbolic(int x) {
163   int ret = toascii(x);
164   (void)ret;
165 
166   clang_analyzer_eval(EOF <= x && x <= 255); // \
167   // report-warning{{TRUE}} \
168   // bugpath-warning{{TRUE}} \
169   // bugpath-note{{TRUE}} \
170   // bugpath-note{{Left side of '&&' is true}} \
171   // bugpath-note{{'x' is <= 255}}
172 }
173 
174 void test_toascii_symbolic2(int x) {
175   if (x > 255) { // \
176     // bugpath-note{{Assuming 'x' is > 255}} \
177     // bugpath-note{{Taking true branch}}
178 
179     int ret = toascii(x); // \
180     // report-warning{{Function argument constraint is not satisfied}} \
181     // report-note{{}} \
182     // bugpath-warning{{Function argument constraint is not satisfied}} \
183     // bugpath-note{{}} \
184     // bugpath-note{{Function argument constraint is not satisfied}}
185 
186     (void)ret;
187   }
188 }
189 
190 typedef struct FILE FILE;
191 typedef typeof(sizeof(int)) size_t;
192 size_t fread(void *restrict, size_t, size_t, FILE *restrict);
193 void test_notnull_concrete(FILE *fp) {
194   fread(0, sizeof(int), 10, fp); // \
195   // report-warning{{Function argument constraint is not satisfied}} \
196   // report-note{{}} \
197   // bugpath-warning{{Function argument constraint is not satisfied}} \
198   // bugpath-note{{}} \
199   // bugpath-note{{Function argument constraint is not satisfied}}
200 }
201 void test_notnull_symbolic(FILE *fp, int *buf) {
202   fread(buf, sizeof(int), 10, fp);
203   clang_analyzer_eval(buf != 0); // \
204   // report-warning{{TRUE}} \
205   // bugpath-warning{{TRUE}} \
206   // bugpath-note{{TRUE}} \
207   // bugpath-note{{'buf' is not equal to null}}
208 }
209 void test_notnull_symbolic2(FILE *fp, int *buf) {
210   if (!buf)                          // bugpath-note{{Assuming 'buf' is null}} \
211             // bugpath-note{{Taking true branch}}
212     fread(buf, sizeof(int), 10, fp); // \
213     // report-warning{{Function argument constraint is not satisfied}} \
214     // report-note{{}} \
215     // bugpath-warning{{Function argument constraint is not satisfied}} \
216     // bugpath-note{{}} \
217     // bugpath-note{{Function argument constraint is not satisfied}}
218 }
219 void test_no_node_after_bug(FILE *fp, size_t size, size_t n, void *buf) {
220   if (fp) // \
221   // bugpath-note{{Assuming 'fp' is null}} \
222   // bugpath-note{{Taking false branch}}
223     return;
224   size_t ret = fread(buf, size, n, fp); // \
225   // report-warning{{Function argument constraint is not satisfied}} \
226   // report-note{{}} \
227   // bugpath-warning{{Function argument constraint is not satisfied}} \
228   // bugpath-note{{}} \
229   // bugpath-note{{Function argument constraint is not satisfied}}
230   clang_analyzer_warnIfReached(); // not reachable
231 }
232 
233 typedef __WCHAR_TYPE__ wchar_t;
234 // This is one test case for the ARR38-C SEI-CERT rule.
235 void ARR38_C_F(FILE *file) {
236   enum { BUFFER_SIZE = 1024 };
237   wchar_t wbuf[BUFFER_SIZE]; // bugpath-note{{'wbuf' initialized here}}
238 
239   const size_t size = sizeof(*wbuf);   // bugpath-note{{'size' initialized to}}
240   const size_t nitems = sizeof(wbuf);  // bugpath-note{{'nitems' initialized to}}
241 
242   // The 3rd parameter should be the number of elements to read, not
243   // the size in bytes.
244   fread(wbuf, size, nitems, file); // \
245   // report-warning{{Function argument constraint is not satisfied}} \
246   // report-note{{}} \
247   // bugpath-warning{{Function argument constraint is not satisfied}} \
248   // bugpath-note{{}} \
249   // bugpath-note{{Function argument constraint is not satisfied}}
250 }
251 
252 int __two_constrained_args(int, int);
253 void test_constraints_on_multiple_args(int x, int y) {
254   // State split should not happen here. I.e. x == 1 should not be evaluated
255   // FALSE.
256   __two_constrained_args(x, y);
257   //NOTE! Because of the second `clang_analyzer_eval` call we have two bug
258   clang_analyzer_eval(x == 1); // \
259   // report-warning{{TRUE}} \
260   // bugpath-warning{{TRUE}} \
261   // bugpath-note{{TRUE}}
262   clang_analyzer_eval(y == 1); // \
263   // report-warning{{TRUE}} \
264   // bugpath-warning{{TRUE}} \
265   // bugpath-note{{TRUE}}
266 }
267 
268 int __arg_constrained_twice(int);
269 void test_multiple_constraints_on_same_arg(int x) {
270   __arg_constrained_twice(x);
271   clang_analyzer_eval(x < 1 || x > 2); // \
272   // report-warning{{TRUE}} \
273   // bugpath-warning{{TRUE}} \
274   // bugpath-note{{TRUE}} \
275   // bugpath-note{{Assuming 'x' is < 1}} \
276   // bugpath-note{{Left side of '||' is true}}
277 }
278 
279 int __variadic(void *stream, const char *format, ...);
280 void test_arg_constraint_on_variadic_fun(void) {
281   __variadic(0, "%d%d", 1, 2); // \
282   // report-warning{{Function argument constraint is not satisfied}} \
283   // report-note{{}} \
284   // bugpath-warning{{Function argument constraint is not satisfied}} \
285   // bugpath-note{{}} \
286   // bugpath-note{{Function argument constraint is not satisfied}}
287 }
288 
289 int __buf_size_arg_constraint(const void *, size_t);
290 void test_buf_size_concrete(void) {
291   char buf[3];                       // bugpath-note{{'buf' initialized here}}
292   __buf_size_arg_constraint(buf, 4); // \
293   // report-warning{{Function argument constraint is not satisfied}} \
294   // report-note{{}} \
295   // bugpath-warning{{Function argument constraint is not satisfied}} \
296   // bugpath-note{{}} \
297   // bugpath-note{{Function argument constraint is not satisfied}}
298 }
299 void test_buf_size_symbolic(int s) {
300   char buf[3];
301   __buf_size_arg_constraint(buf, s);
302   clang_analyzer_eval(s <= 3); // \
303   // report-warning{{TRUE}} \
304   // bugpath-warning{{TRUE}} \
305   // bugpath-note{{TRUE}} \
306   // bugpath-note{{'s' is <= 3}}
307 }
308 void test_buf_size_symbolic_and_offset(int s) {
309   char buf[3];
310   __buf_size_arg_constraint(buf + 1, s);
311   clang_analyzer_eval(s <= 2); // \
312   // report-warning{{TRUE}} \
313   // bugpath-warning{{TRUE}} \
314   // bugpath-note{{TRUE}} \
315   // bugpath-note{{'s' is <= 2}}
316 }
317 
318 int __buf_size_arg_constraint_mul(const void *, size_t, size_t);
319 void test_buf_size_concrete_with_multiplication(void) {
320   short buf[3];                                         // bugpath-note{{'buf' initialized here}}
321   __buf_size_arg_constraint_mul(buf, 4, sizeof(short)); // \
322   // report-warning{{Function argument constraint is not satisfied}} \
323   // report-note{{}} \
324   // bugpath-warning{{Function argument constraint is not satisfied}} \
325   // bugpath-note{{}} \
326   // bugpath-note{{Function argument constraint is not satisfied}}
327 }
328 void test_buf_size_symbolic_with_multiplication(size_t s) {
329   short buf[3];
330   __buf_size_arg_constraint_mul(buf, s, sizeof(short));
331   clang_analyzer_eval(s * sizeof(short) <= 6); // \
332   // report-warning{{TRUE}} \
333   // bugpath-warning{{TRUE}} \
334   // bugpath-note{{TRUE}}
335 }
336 void test_buf_size_symbolic_and_offset_with_multiplication(size_t s) {
337   short buf[3];
338   __buf_size_arg_constraint_mul(buf + 1, s, sizeof(short));
339   clang_analyzer_eval(s * sizeof(short) <= 4); // \
340   // report-warning{{TRUE}} \
341   // bugpath-warning{{TRUE}} \
342   // bugpath-note{{TRUE}}
343 }
344 
345 // The minimum buffer size for this function is set to 10.
346 int __buf_size_arg_constraint_concrete(const void *);
347 void test_min_buf_size(void) {
348   char buf[9];// bugpath-note{{'buf' initialized here}}
349   __buf_size_arg_constraint_concrete(buf); // \
350   // report-warning{{Function argument constraint is not satisfied}} \
351   // report-note{{}} \
352   // bugpath-warning{{Function argument constraint is not satisfied}} \
353   // bugpath-note{{}} \
354   // bugpath-note{{Function argument constraint is not satisfied}}
355 }
356