Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / clang / test / Analysis / std-c-library-functions-arg-constraints.c
blob0b817dda98c727f438b910f73eeeed7946cc4ace
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=unix.StdCLibraryFunctions \
5 // RUN: -analyzer-config unix.StdCLibraryFunctions:ModelPOSIX=true \
6 // RUN: -analyzer-checker=debug.StdCLibraryFunctionsTester \
7 // RUN: -analyzer-checker=debug.ExprInspection \
8 // RUN: -triple x86_64-unknown-linux-gnu \
9 // RUN: -verify=report
11 // Check the bugpath related to the reports.
12 // RUN: %clang_analyze_cc1 %s \
13 // RUN: -analyzer-checker=core \
14 // RUN: -analyzer-checker=unix.StdCLibraryFunctions \
15 // RUN: -analyzer-config unix.StdCLibraryFunctions:ModelPOSIX=true \
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
22 #include "Inputs/std-c-library-functions-POSIX.h"
24 void clang_analyzer_eval(int);
25 void clang_analyzer_warnIfReached();
27 int glob;
29 void test_alnum_concrete(int v) {
30 int ret = isalnum(256); // \
31 // report-warning{{The 1st argument to 'isalnum' is 256 but should be an unsigned char value or EOF}} \
32 // bugpath-warning{{The 1st argument to 'isalnum' is 256 but should be an unsigned char value or EOF}} \
33 // bugpath-note{{The 1st argument to 'isalnum' is 256 but should be an unsigned char value or EOF}}
34 (void)ret;
37 void test_alnum_symbolic(int x) {
38 int ret = isalnum(x);
39 (void)ret;
41 clang_analyzer_eval(EOF <= x && x <= 255); // \
42 // report-warning{{TRUE}} \
43 // bugpath-warning{{TRUE}} \
44 // bugpath-note{{TRUE}} \
45 // bugpath-note{{Left side of '&&' is true}} \
46 // bugpath-note{{'x' is <= 255}}
49 void test_alnum_symbolic2(int x) {
50 if (x > 255) { // \
51 // bugpath-note{{Assuming 'x' is > 255}} \
52 // bugpath-note{{Taking true branch}}
54 int ret = isalnum(x); // \
55 // report-warning{{The 1st argument to 'isalnum' is >= 256 but should be an unsigned char value or EOF}} \
56 // bugpath-warning{{The 1st argument to 'isalnum' is >= 256 but should be an unsigned char value or EOF}} \
57 // bugpath-note{{The 1st argument to 'isalnum' is >= 256 but should be an unsigned char value or EOF}}
59 (void)ret;
63 void test_toupper_concrete(int v) {
64 int ret = toupper(256); // \
65 // report-warning{{The 1st argument to 'toupper' is 256 but should be an unsigned char value or EOF}} \
66 // bugpath-warning{{The 1st argument to 'toupper' is 256 but should be an unsigned char value or EOF}} \
67 // bugpath-note{{The 1st argument to 'toupper' is 256 but should be an unsigned char value or EOF}}
68 (void)ret;
71 void test_toupper_symbolic(int x) {
72 int ret = toupper(x);
73 (void)ret;
75 clang_analyzer_eval(EOF <= x && x <= 255); // \
76 // report-warning{{TRUE}} \
77 // bugpath-warning{{TRUE}} \
78 // bugpath-note{{TRUE}} \
79 // bugpath-note{{Left side of '&&' is true}} \
80 // bugpath-note{{'x' is <= 255}}
83 void test_toupper_symbolic2(int x) {
84 if (x > 255) { // \
85 // bugpath-note{{Assuming 'x' is > 255}} \
86 // bugpath-note{{Taking true branch}}
88 int ret = toupper(x); // \
89 // report-warning{{The 1st argument to 'toupper' is >= 256 but should be an unsigned char value or EOF}} \
90 // bugpath-warning{{The 1st argument to 'toupper' is >= 256 but should be an unsigned char value or EOF}} \
91 // bugpath-note{{The 1st argument to 'toupper' is >= 256 but should be an unsigned char value or EOF}}
93 (void)ret;
97 void test_tolower_concrete(int v) {
98 int ret = tolower(256); // \
99 // report-warning{{The 1st argument to 'tolower' is 256 but should be an unsigned char value or EOF}} \
100 // bugpath-warning{{The 1st argument to 'tolower' is 256 but should be an unsigned char value or EOF}} \
101 // bugpath-note{{The 1st argument to 'tolower' is 256 but should be an unsigned char value or EOF}}
102 (void)ret;
105 void test_tolower_symbolic(int x) {
106 int ret = tolower(x);
107 (void)ret;
109 clang_analyzer_eval(EOF <= x && x <= 255); // \
110 // report-warning{{TRUE}} \
111 // bugpath-warning{{TRUE}} \
112 // bugpath-note{{TRUE}} \
113 // bugpath-note{{Left side of '&&' is true}} \
114 // bugpath-note{{'x' is <= 255}}
117 void test_tolower_symbolic2(int x) {
118 if (x > 255) { // \
119 // bugpath-note{{Assuming 'x' is > 255}} \
120 // bugpath-note{{Taking true branch}}
122 int ret = tolower(x); // \
123 // report-warning{{The 1st argument to 'tolower' is >= 256 but should be an unsigned char value or EOF}} \
124 // bugpath-warning{{The 1st argument to 'tolower' is >= 256 but should be an unsigned char value or EOF}} \
125 // bugpath-note{{The 1st argument to 'tolower' is >= 256 but should be an unsigned char value or EOF}}
127 (void)ret;
131 void test_toascii_concrete(int v) {
132 int ret = toascii(256); // \
133 // report-warning{{The 1st argument to 'toascii' is 256 but should be an unsigned char value or EOF}} \
134 // bugpath-warning{{The 1st argument to 'toascii' is 256 but should be an unsigned char value or EOF}} \
135 // bugpath-note{{The 1st argument to 'toascii' is 256 but should be an unsigned char value or EOF}}
136 (void)ret;
139 void test_toascii_symbolic(int x) {
140 int ret = toascii(x);
141 (void)ret;
143 clang_analyzer_eval(EOF <= x && x <= 255); // \
144 // report-warning{{TRUE}} \
145 // bugpath-warning{{TRUE}} \
146 // bugpath-note{{TRUE}} \
147 // bugpath-note{{Left side of '&&' is true}} \
148 // bugpath-note{{'x' is <= 255}}
151 void test_toascii_symbolic2(int x) {
152 if (x > 255) { // \
153 // bugpath-note{{Assuming 'x' is > 255}} \
154 // bugpath-note{{Taking true branch}}
156 int ret = toascii(x); // \
157 // report-warning{{The 1st argument to 'toascii' is >= 256 but should be an unsigned char value or EOF}} \
158 // bugpath-warning{{The 1st argument to 'toascii' is >= 256 but should be an unsigned char value or EOF}} \
159 // bugpath-note{{The 1st argument to 'toascii' is >= 256 but should be an unsigned char value or EOF}}
161 (void)ret;
165 void test_notnull_concrete(FILE *fp) {
166 fread(0, sizeof(int), 10, fp); // \
167 // report-warning{{The 1st argument to 'fread' is NULL but should not be NULL}} \
168 // bugpath-warning{{The 1st argument to 'fread' is NULL but should not be NULL}} \
169 // bugpath-note{{The 1st argument to 'fread' is NULL but should not be NULL}}
171 void test_notnull_symbolic(FILE *fp, int *buf) {
172 fread(buf, sizeof(int), 10, fp);
173 clang_analyzer_eval(buf != 0); // \
174 // report-warning{{TRUE}} \
175 // bugpath-warning{{TRUE}} \
176 // bugpath-note{{TRUE}} \
177 // bugpath-note{{'buf' is not equal to null}}
179 void test_notnull_symbolic2(FILE *fp, int *buf) {
180 if (!buf) // bugpath-note{{Assuming 'buf' is null}} \
181 // bugpath-note{{Taking true branch}}
182 fread(buf, sizeof(int), 10, fp); // \
183 // report-warning{{The 1st argument to 'fread' is NULL but should not be NULL}} \
184 // bugpath-warning{{The 1st argument to 'fread' is NULL but should not be NULL}} \
185 // bugpath-note{{The 1st argument to 'fread' is NULL but should not be NULL}}
188 int __not_null_buffer(void *, int, int);
190 void test_notnull_buffer_1(void *buf) {
191 __not_null_buffer(buf, 0, 1);
192 clang_analyzer_eval(buf != 0); // \
193 // report-warning{{TRUE}} \
194 // bugpath-warning{{TRUE}} \
195 // report-warning{{FALSE}} \
196 // bugpath-warning{{FALSE}} \
197 // bugpath-note{{TRUE}} \
198 // bugpath-note{{FALSE}} \
199 // bugpath-note{{Assuming 'buf' is equal to null}} \
200 // bugpath-note{{Assuming 'buf' is not equal to null}}
203 void test_notnull_buffer_2(void *buf) {
204 __not_null_buffer(buf, 1, 0);
205 clang_analyzer_eval(buf != 0); // \
206 // report-warning{{TRUE}} \
207 // bugpath-warning{{TRUE}} \
208 // report-warning{{FALSE}} \
209 // bugpath-warning{{FALSE}} \
210 // bugpath-note{{TRUE}} \
211 // bugpath-note{{FALSE}} \
212 // bugpath-note{{Assuming 'buf' is equal to null}} \
213 // bugpath-note{{Assuming 'buf' is not equal to null}}
216 void test_notnull_buffer_3(void *buf) {
217 __not_null_buffer(buf, 1, 1);
218 clang_analyzer_eval(buf != 0); // \
219 // report-warning{{TRUE}} \
220 // bugpath-warning{{TRUE}} \
221 // bugpath-note{{TRUE}} \
222 // bugpath-note{{'buf' is not equal to null}}
225 void test_no_node_after_bug(FILE *fp, size_t size, size_t n, void *buf) {
226 if (fp) // \
227 // bugpath-note{{Assuming 'fp' is null}} \
228 // bugpath-note{{Taking false branch}}
229 return;
230 size_t ret = fread(buf, size, n, fp); // \
231 // report-warning{{The 4th argument to 'fread' is NULL but should not be NULL}} \
232 // bugpath-warning{{The 4th argument to 'fread' is NULL but should not be NULL}} \
233 // bugpath-note{{The 4th argument to 'fread' is NULL but should not be NULL}}
234 clang_analyzer_warnIfReached(); // not reachable
237 // This is one test case for the ARR38-C SEI-CERT rule.
238 void ARR38_C_F(FILE *file) {
239 enum { BUFFER_SIZE = 1024 };
240 wchar_t wbuf[BUFFER_SIZE]; // bugpath-note{{'wbuf' initialized here}}
242 const size_t size = sizeof(*wbuf); // bugpath-note{{'size' initialized to}}
243 const size_t nitems = sizeof(wbuf); // bugpath-note{{'nitems' initialized to}}
245 // The 3rd parameter should be the number of elements to read, not
246 // the size in bytes.
247 fread(wbuf, size, nitems, file); // \
248 // report-warning{{The 1st argument to 'fread' is a buffer with size 4096 but should be a buffer with size equal to or greater than the value of the 2nd argument (which is 4) times the 3rd argument (which is 4096)}} \
249 // bugpath-warning{{The 1st argument to 'fread' is a buffer with size 4096 but should be a buffer with size equal to or greater than the value of the 2nd argument (which is 4) times the 3rd argument (which is 4096)}} \
250 // bugpath-note{{The 1st argument to 'fread' is a buffer with size 4096 but should be a buffer with size equal to or greater than the value of the 2nd argument (which is 4) times the 3rd argument (which is 4096)}}
253 int __two_constrained_args(int, int);
254 void test_constraints_on_multiple_args(int x, int y) {
255 // State split should not happen here. I.e. x == 1 should not be evaluated
256 // FALSE.
257 __two_constrained_args(x, y);
258 //NOTE! Because of the second `clang_analyzer_eval` call we have two bug
259 clang_analyzer_eval(x == 1); // \
260 // report-warning{{TRUE}} \
261 // bugpath-warning{{TRUE}} \
262 // bugpath-note{{TRUE}}
263 clang_analyzer_eval(y == 1); // \
264 // report-warning{{TRUE}} \
265 // bugpath-warning{{TRUE}} \
266 // bugpath-note{{TRUE}}
269 int __arg_constrained_twice(int);
270 void test_multiple_constraints_on_same_arg(int x) {
271 __arg_constrained_twice(x);
272 clang_analyzer_eval(x < 1 || x > 2); // \
273 // report-warning{{TRUE}} \
274 // bugpath-warning{{TRUE}} \
275 // bugpath-note{{TRUE}} \
276 // bugpath-note{{Assuming 'x' is < 1}} \
277 // bugpath-note{{Left side of '||' is true}}
280 int __variadic(void *stream, const char *format, ...);
281 void test_arg_constraint_on_variadic_fun(void) {
282 __variadic(0, "%d%d", 1, 2); // \
283 // report-warning{{The 1st argument to '__variadic' is NULL but should not be NULL}} \
284 // bugpath-warning{{The 1st argument to '__variadic' is NULL but should not be NULL}} \
285 // bugpath-note{{The 1st argument to '__variadic' is NULL but should not be NULL}}
288 int __buf_size_arg_constraint(const void *, size_t);
289 void test_buf_size_concrete(void) {
290 char buf[3]; // bugpath-note{{'buf' initialized here}}
291 __buf_size_arg_constraint(buf, 4); // \
292 // report-warning{{The 1st argument to '__buf_size_arg_constraint' is a buffer with size 3 but should be a buffer with size equal to or greater than the value of the 2nd argument (which is 4)}} \
293 // bugpath-warning{{The 1st argument to '__buf_size_arg_constraint' is a buffer with size 3 but should be a buffer with size equal to or greater than the value of the 2nd argument (which is 4)}} \
294 // bugpath-note{{The 1st argument to '__buf_size_arg_constraint' is a buffer with size 3 but should be a buffer with size equal to or greater than the value of the 2nd argument (which is 4)}}
296 void test_buf_size_symbolic(int s) {
297 char buf[3];
298 __buf_size_arg_constraint(buf, s);
299 clang_analyzer_eval(s <= 3); // \
300 // report-warning{{TRUE}} \
301 // bugpath-warning{{TRUE}} \
302 // bugpath-note{{TRUE}} \
303 // bugpath-note{{'s' is <= 3}}
305 void test_buf_size_symbolic_and_offset(int s) {
306 char buf[3];
307 __buf_size_arg_constraint(buf + 1, s);
308 clang_analyzer_eval(s <= 2); // \
309 // report-warning{{TRUE}} \
310 // bugpath-warning{{TRUE}} \
311 // bugpath-note{{TRUE}} \
312 // bugpath-note{{'s' is <= 2}}
315 int __buf_size_arg_constraint_mul(const void *, size_t, size_t);
316 void test_buf_size_concrete_with_multiplication(void) {
317 short buf[3]; // bugpath-note{{'buf' initialized here}}
318 __buf_size_arg_constraint_mul(buf, 4, sizeof(short)); // \
319 // report-warning{{The 1st argument to '__buf_size_arg_constraint_mul' is a buffer with size 6 but should be a buffer with size equal to or greater than the value of the 2nd argument (which is 4) times the 3rd argument (which is 2)}} \
320 // bugpath-warning{{The 1st argument to '__buf_size_arg_constraint_mul' is a buffer with size 6 but should be a buffer with size equal to or greater than the value of the 2nd argument (which is 4) times the 3rd argument (which is 2)}} \
321 // bugpath-note{{The 1st argument to '__buf_size_arg_constraint_mul' is a buffer with size 6 but should be a buffer with size equal to or greater than the value of the 2nd argument (which is 4) times the 3rd argument (which is 2)}}
323 void test_buf_size_symbolic_with_multiplication(size_t s) {
324 short buf[3];
325 __buf_size_arg_constraint_mul(buf, s, sizeof(short));
326 clang_analyzer_eval(s * sizeof(short) <= 6); // \
327 // report-warning{{TRUE}} \
328 // bugpath-warning{{TRUE}} \
329 // bugpath-note{{TRUE}}
331 void test_buf_size_symbolic_and_offset_with_multiplication(size_t s) {
332 short buf[3];
333 __buf_size_arg_constraint_mul(buf + 1, s, sizeof(short));
334 clang_analyzer_eval(s * sizeof(short) <= 4); // \
335 // report-warning{{TRUE}} \
336 // bugpath-warning{{TRUE}} \
337 // bugpath-note{{TRUE}}
340 // The minimum buffer size for this function is set to 10.
341 int __buf_size_arg_constraint_concrete(const void *);
342 void test_min_buf_size(void) {
343 char buf[9];// bugpath-note{{'buf' initialized here}}
344 __buf_size_arg_constraint_concrete(buf); // \
345 // report-warning{{The 1st argument to '__buf_size_arg_constraint_concrete' is a buffer with size 9 but should be a buffer with size equal to or greater than 10}} \
346 // bugpath-warning{{The 1st argument to '__buf_size_arg_constraint_concrete' is a buffer with size 9 but should be a buffer with size equal to or greater than 10}} \
347 // bugpath-note{{The 1st argument to '__buf_size_arg_constraint_concrete' is a buffer with size 9 but should be a buffer with size equal to or greater than 10}}
350 void test_file_fd_at_functions() {
351 (void)linkat(-22, "from", AT_FDCWD, "to", 0); // \
352 // report-warning{{The 1st argument to 'linkat' is -22 but should be a valid file descriptor or AT_FDCWD}} \
353 // bugpath-warning{{The 1st argument to 'linkat' is -22 but should be a valid file descriptor or AT_FDCWD}} \
354 // bugpath-note{{The 1st argument to 'linkat' is -22 but should be a valid file descriptor or AT_FDCWD}}
356 // no warning for these functions if the AT_FDCWD value is used
357 (void)openat(AT_FDCWD, "path", 0);
358 (void)linkat(AT_FDCWD, "from", AT_FDCWD, "to", 0);
359 (void)faccessat(AT_FDCWD, "path", 0, 0);
360 (void)symlinkat("oldpath", AT_FDCWD, "newpath");
361 (void)mkdirat(AT_FDCWD, "path", 0);
362 (void)mknodat(AT_FDCWD, "path", 0, 0);
363 (void)fchmodat(AT_FDCWD, "path", 0, 0);
364 (void)fchownat(AT_FDCWD, "path", 0, 0, 0);
365 (void)linkat(AT_FDCWD, "oldpath", AT_FDCWD, "newpath", 0);
366 (void)unlinkat(AT_FDCWD, "newpath", 0);
367 struct stat St;
368 (void)fstatat(AT_FDCWD, "newpath", &St, 0);
369 char Buf[10];
370 (void)readlinkat(AT_FDCWD, "newpath", Buf, 10);
371 (void)renameat(AT_FDCWD, "oldpath", AT_FDCWD, "newpath");