1 // RUN: %clang_analyze_cc1 -triple=x86_64-pc-linux-gnu -analyzer-checker=core,unix.Stream,debug.ExprInspection \
2 // RUN: -analyzer-config eagerly-assume=false,unix.Stream:Pedantic=true -verify %s
3 // RUN: %clang_analyze_cc1 -triple=armv8-none-linux-eabi -analyzer-checker=core,unix.Stream,debug.ExprInspection \
4 // RUN: -analyzer-config eagerly-assume=false,unix.Stream:Pedantic=true -verify %s
5 // RUN: %clang_analyze_cc1 -triple=aarch64-linux-gnu -analyzer-checker=core,unix.Stream,debug.ExprInspection \
6 // RUN: -analyzer-config eagerly-assume=false,unix.Stream:Pedantic=true -verify %s
7 // RUN: %clang_analyze_cc1 -triple=hexagon -analyzer-checker=core,unix.Stream,debug.ExprInspection \
8 // RUN: -analyzer-config eagerly-assume=false,unix.Stream:Pedantic=true -verify %s
10 #include "Inputs/system-header-simulator.h"
11 #include "Inputs/system-header-simulator-for-malloc.h"
12 #include "Inputs/system-header-simulator-for-valist.h"
14 void clang_analyzer_eval(int);
16 void check_fread(void) {
18 fread(0, 0, 0, fp
); // expected-warning {{Stream pointer might be NULL}}
22 void check_fwrite(void) {
24 fwrite(0, 0, 0, fp
); // expected-warning {{Stream pointer might be NULL}}
28 void check_fgetc(void) {
30 fgetc(fp
); // expected-warning {{Stream pointer might be NULL}}
34 void check_fgets(void) {
37 fgets(buf
, sizeof(buf
), fp
); // expected-warning {{Stream pointer might be NULL}}
41 void check_fputc(void) {
43 fputc('A', fp
); // expected-warning {{Stream pointer might be NULL}}
47 void check_fputs(void) {
49 fputs("ABC", fp
); // expected-warning {{Stream pointer might be NULL}}
53 void check_fprintf(void) {
55 fprintf(fp
, "ABC"); // expected-warning {{Stream pointer might be NULL}}
59 void check_fscanf(void) {
61 fscanf(fp
, "ABC"); // expected-warning {{Stream pointer might be NULL}}
65 void check_ungetc(void) {
67 ungetc('A', fp
); // expected-warning {{Stream pointer might be NULL}}
71 void check_fseek(void) {
73 fseek(fp
, 0, 0); // expected-warning {{Stream pointer might be NULL}}
77 void check_fseeko(void) {
79 fseeko(fp
, 0, 0); // expected-warning {{Stream pointer might be NULL}}
83 void check_ftell(void) {
85 ftell(fp
); // expected-warning {{Stream pointer might be NULL}}
89 void check_ftello(void) {
91 ftello(fp
); // expected-warning {{Stream pointer might be NULL}}
95 void check_rewind(void) {
97 rewind(fp
); // expected-warning {{Stream pointer might be NULL}}
101 void check_fgetpos(void) {
102 FILE *fp
= tmpfile();
104 fgetpos(fp
, &pos
); // expected-warning {{Stream pointer might be NULL}}
108 void check_fsetpos(void) {
109 FILE *fp
= tmpfile();
111 fsetpos(fp
, &pos
); // expected-warning {{Stream pointer might be NULL}}
115 void check_clearerr(void) {
116 FILE *fp
= tmpfile();
117 clearerr(fp
); // expected-warning {{Stream pointer might be NULL}}
121 void check_feof(void) {
122 FILE *fp
= tmpfile();
123 feof(fp
); // expected-warning {{Stream pointer might be NULL}}
127 void check_ferror(void) {
128 FILE *fp
= tmpfile();
129 ferror(fp
); // expected-warning {{Stream pointer might be NULL}}
133 void check_fileno(void) {
134 FILE *fp
= tmpfile();
135 fileno(fp
); // expected-warning {{Stream pointer might be NULL}}
140 FILE *p
= fopen("foo", "r");
142 fread(buf
, 1, 1, p
); // expected-warning {{Stream pointer might be NULL}}
146 void f_dopen(int fd
) {
147 FILE *F
= fdopen(fd
, "r");
149 fread(buf
, 1, 1, F
); // expected-warning {{Stream pointer might be NULL}}
153 void f_vfprintf(int fd
, va_list args
) {
154 FILE *F
= fdopen(fd
, "r");
155 vfprintf(F
, "%d", args
); // expected-warning {{Stream pointer might be NULL}}
159 void f_vfscanf(int fd
, va_list args
) {
160 FILE *F
= fdopen(fd
, "r");
161 vfscanf(F
, "%u", args
); // expected-warning {{Stream pointer might be NULL}}
166 FILE *p
= fopen("foo", "r");
169 fseek(p
, 1, SEEK_SET
); // no-warning
170 fseek(p
, 1, 3); // expected-warning {{The whence argument to fseek() should be SEEK_SET, SEEK_END, or SEEK_CUR}}
175 FILE *p
= fopen("foo", "r");
178 fseeko(p
, 1, SEEK_SET
); // no-warning
179 fseeko(p
, 1, 3); // expected-warning {{The whence argument to fseek() should be SEEK_SET, SEEK_END, or SEEK_CUR}}
183 void f_double_close(void) {
184 FILE *p
= fopen("foo", "r");
188 fclose(p
); // expected-warning {{Use of a stream that might be already closed}}
191 void f_double_close_alias(void) {
192 FILE *p1
= fopen("foo", "r");
197 fclose(p2
); // expected-warning {{Use of a stream that might be already closed}}
200 void f_use_after_close(void) {
201 FILE *p
= fopen("foo", "r");
205 clearerr(p
); // expected-warning {{Use of a stream that might be already closed}}
208 void f_open_after_close(void) {
209 FILE *p
= fopen("foo", "r");
213 p
= fopen("foo", "r");
219 void f_reopen_after_close(void) {
220 FILE *p
= fopen("foo", "r");
224 // Allow reopen after close.
225 p
= freopen("foo", "w", p
);
232 FILE *p
= fopen("foo.c", "r");
236 return; // expected-warning {{Opened stream never closed. Potential resource leak}}
240 FILE *f_null_checked(void) {
241 FILE *p
= fopen("foo.c", "r");
243 return p
; // no-warning
248 void pr7831(FILE *fp
) {
249 fclose(fp
); // no-warning
252 // PR 8081 - null pointer crash when 'whence' is not an integer constant
253 void pr8081(FILE *stream
, long offset
, int whence
) {
254 fseek(stream
, offset
, whence
);
257 void check_freopen_1(void) {
258 FILE *f1
= freopen("foo.c", "r", (FILE *)0); // expected-warning {{Stream pointer might be NULL}}
259 f1
= freopen(0, "w", (FILE *)0x123456); // Do not report this as error.
262 void check_freopen_2(void) {
263 FILE *f1
= fopen("foo.c", "r");
265 FILE *f2
= freopen(0, "w", f1
);
267 // Check if f1 and f2 point to the same stream.
269 fclose(f2
); // expected-warning {{Use of a stream that might be already closed}}
272 // f1 is non-NULL but points to a possibly invalid stream.
273 rewind(f1
); // expected-warning {{Stream might be invalid}}
274 // f2 is NULL but the previous error stops the checker.
280 void check_freopen_3(void) {
281 FILE *f1
= fopen("foo.c", "r");
283 // Unchecked result of freopen.
284 // The f1 may be invalid after this call.
286 rewind(f1
); // expected-warning {{Stream might be invalid}}
291 extern FILE *GlobalF
;
292 extern void takeFile(FILE *);
294 void check_escape1(void) {
298 fwrite("1", 1, 1, F
); // may fail
300 fwrite("1", 1, 1, F
); // no warning
303 void check_escape2(void) {
307 fwrite("1", 1, 1, F
); // may fail
309 fwrite("1", 1, 1, F
); // no warning
312 void check_escape3(void) {
317 F
= freopen(0, "w", F
);
320 fwrite("1", 1, 1, F
); // may fail
321 fwrite("1", 1, 1, F
); // no warning
324 void check_escape4(void) {
328 fwrite("1", 1, 1, F
); // may fail
330 // no escape at a non-StreamChecker-handled system call
333 fwrite("1", 1, 1, F
); // expected-warning {{might be 'indeterminate'}}
338 _Noreturn
void handle_error(void);
340 void check_leak_noreturn_1(void) {
341 FILE *F1
= tmpfile();
345 handle_error(); // no warning
348 } // expected-warning {{Opened stream never closed. Potential resource leak}}
350 // Check that "location uniqueing" works.
351 // This results in reporting only one occurence of resource leak for a stream.
352 void check_leak_noreturn_2(void) {
353 FILE *F1
= tmpfile();
357 return; // no warning
360 } // expected-warning {{Opened stream never closed. Potential resource leak}}
361 // FIXME: This warning should be placed at the `return` above.
362 // See https://reviews.llvm.org/D83120 about details.
364 void fflush_after_fclose(void) {
367 fflush(NULL
); // no-warning
370 if ((Ret
= fflush(F
)) != 0)
371 clang_analyzer_eval(Ret
== EOF
); // expected-warning {{TRUE}}
373 fflush(F
); // expected-warning {{Use of a stream that might be already closed}}
376 void fflush_on_open_failed_stream(void) {
379 fflush(F
); // no-warning
385 void getline_null_file() {
388 getline(&buffer
, &n
, NULL
); // expected-warning {{Stream pointer might be NULL}}
391 void getdelim_null_file() {
394 getdelim(&buffer
, &n
, '\n', NULL
); // expected-warning {{Stream pointer might be NULL}}
397 void getline_buffer_on_error() {
398 FILE *file
= fopen("file.txt", "r");
405 if (getline(&line
, &len
, file
) == -1) {
406 if (line
[0] == '\0') {} // expected-warning {{The left operand of '==' is a garbage value}}
408 if (line
[0] == '\0') {} // no warning
415 void getline_ret_value() {
416 FILE *file
= fopen("file.txt", "r");
423 ssize_t r
= getline(&buffer
, &n
, file
);
426 // The return value does *not* include the terminating null byte.
427 // The buffer must be large enough to include it.
428 clang_analyzer_eval(n
> r
); // expected-warning{{TRUE}}
429 clang_analyzer_eval(buffer
!= NULL
); // expected-warning{{TRUE}}
437 void getline_buffer_size_negative() {
438 FILE *file
= fopen("file.txt", "r");
444 clang_analyzer_eval((ssize_t
)n
>= 0); // expected-warning{{FALSE}}
446 ssize_t r
= getline(&buffer
, &n
, file
);
449 clang_analyzer_eval((ssize_t
)n
> r
); // expected-warning{{TRUE}}
450 clang_analyzer_eval(buffer
!= NULL
); // expected-warning{{TRUE}}
457 void gh_93408_regression(void *buffer
) {
458 FILE *f
= fopen("/tmp/foo.txt", "r");
459 fread(buffer
, 1, 1, f
); // expected-warning {{Stream pointer might be NULL}} no-crash
464 void gh_93408_regression_typedef(VOID
*buffer
) {
465 FILE *f
= fopen("/tmp/foo.txt", "r");
466 fread(buffer
, 1, 1, f
); // expected-warning {{Stream pointer might be NULL}} no-crash
480 void gh_93408_regression_FAM(struct FAM
*p
) {
481 FILE *f
= fopen("/tmp/foo.txt", "r");
482 fread(p
->tail
, 1, 1, f
); // expected-warning {{Stream pointer might be NULL}}
486 void gh_93408_regression_FAM0(struct FAM0
*p
) {
487 FILE *f
= fopen("/tmp/foo.txt", "r");
488 fread(p
->tail
, 1, 1, f
); // expected-warning {{Stream pointer might be NULL}}
496 void gh_93408_regression_ZeroSized(struct ZeroSized
*buffer
) {
497 FILE *f
= fopen("/tmp/foo.txt", "r");
498 fread(buffer
, 1, 1, f
); // expected-warning {{Stream pointer might be NULL}} no-crash
502 extern FILE *non_standard_stream_ptr
;
503 void test_fopen_does_not_alias_with_standard_streams(void) {
504 FILE *f
= fopen("file", "r");
506 clang_analyzer_eval(f
== stdin
); // expected-warning {{FALSE}} no-TRUE
507 clang_analyzer_eval(f
== stdout
); // expected-warning {{FALSE}} no-TRUE
508 clang_analyzer_eval(f
== stderr
); // expected-warning {{FALSE}} no-TRUE
509 clang_analyzer_eval(f
== non_standard_stream_ptr
); // expected-warning {{UNKNOWN}}
513 } // no-leak: 'fclose()' is always called because 'f' cannot be 'stdout'.
515 void reopen_std_stream(void) {
516 FILE *oldStdout
= stdout
;
518 FILE *fp
= fopen("blah", "w");
521 stdout
= fp
; // Let's make them alias.
522 clang_analyzer_eval(fp
== oldStdout
); // expected-warning {{UNKNOWN}}
523 clang_analyzer_eval(fp
== stdout
); // expected-warning {{TRUE}} no-FALSE
524 clang_analyzer_eval(oldStdout
== stdout
); // expected-warning {{UNKNOWN}}
527 void only_success_path_does_not_alias_with_stdout(void) {
529 FILE *f
= fopen("/tmp/foof", "r"); // no-crash