Balázs Kéri 570bf972f5 [clang][analyzer] Remove report of null stream from StreamChecker.
The case of NULL stream passed to stream functions was reported by StreamChecker.
The same condition is checked already by StdLibraryFunctionsChecker and it is
enough to check at one place. The StreamChecker stops now analysis if a passed NULL
stream is encountered but generates no report.
This change removes a dependency between StdCLibraryFunctionArgs checker and
StreamChecker. There is now no more specific message reported by StreamChecker,
the previous weak-dependency is not needed. And StreamChecker can be used
without StdCLibraryFunctions checker or its ModelPOSIX option.

Reviewed By: Szelethus

Differential Revision: https://reviews.llvm.org/D137790
2023-01-09 09:49:08 +01:00

195 lines
4.3 KiB
C

// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.unix.Stream -verify %s
#include "Inputs/system-header-simulator.h"
void f_seek(void) {
FILE *p = fopen("foo", "r");
if (!p)
return;
fseek(p, 1, SEEK_SET); // no-warning
fseek(p, 1, 3); // expected-warning {{The whence argument to fseek() should be SEEK_SET, SEEK_END, or SEEK_CUR}}
fclose(p);
}
void f_double_close(void) {
FILE *p = fopen("foo", "r");
if (!p)
return;
fclose(p);
fclose(p); // expected-warning {{Stream might be already closed}}
}
void f_double_close_alias(void) {
FILE *p1 = fopen("foo", "r");
if (!p1)
return;
FILE *p2 = p1;
fclose(p1);
fclose(p2); // expected-warning {{Stream might be already closed}}
}
void f_use_after_close(void) {
FILE *p = fopen("foo", "r");
if (!p)
return;
fclose(p);
clearerr(p); // expected-warning {{Stream might be already closed}}
}
void f_open_after_close(void) {
FILE *p = fopen("foo", "r");
if (!p)
return;
fclose(p);
p = fopen("foo", "r");
if (!p)
return;
fclose(p);
}
void f_reopen_after_close(void) {
FILE *p = fopen("foo", "r");
if (!p)
return;
fclose(p);
// Allow reopen after close.
p = freopen("foo", "w", p);
if (!p)
return;
fclose(p);
}
void f_leak(int c) {
FILE *p = fopen("foo.c", "r");
if (!p)
return;
if(c)
return; // expected-warning {{Opened stream never closed. Potential resource leak}}
fclose(p);
}
FILE *f_null_checked(void) {
FILE *p = fopen("foo.c", "r");
if (p)
return p; // no-warning
else
return 0;
}
void pr7831(FILE *fp) {
fclose(fp); // no-warning
}
// PR 8081 - null pointer crash when 'whence' is not an integer constant
void pr8081(FILE *stream, long offset, int whence) {
fseek(stream, offset, whence);
}
void check_freopen_1(void) {
FILE *f1 = freopen("foo.c", "r", (FILE *)0); // Not reported by the stream checker.
f1 = freopen(0, "w", (FILE *)0x123456); // Do not report this as error.
}
void check_freopen_2(void) {
FILE *f1 = fopen("foo.c", "r");
if (f1) {
FILE *f2 = freopen(0, "w", f1);
if (f2) {
// Check if f1 and f2 point to the same stream.
fclose(f1);
fclose(f2); // expected-warning {{Stream might be already closed.}}
} else {
// Reopen failed.
// f1 is non-NULL but points to a possibly invalid stream.
rewind(f1); // expected-warning {{Stream might be invalid}}
// f2 is NULL but the previous error stops the checker.
rewind(f2);
}
}
}
void check_freopen_3(void) {
FILE *f1 = fopen("foo.c", "r");
if (f1) {
// Unchecked result of freopen.
// The f1 may be invalid after this call.
freopen(0, "w", f1);
rewind(f1); // expected-warning {{Stream might be invalid}}
fclose(f1);
}
}
extern FILE *GlobalF;
extern void takeFile(FILE *);
void check_escape1(void) {
FILE *F = tmpfile();
if (!F)
return;
fwrite("1", 1, 1, F); // may fail
GlobalF = F;
fwrite("1", 1, 1, F); // no warning
}
void check_escape2(void) {
FILE *F = tmpfile();
if (!F)
return;
fwrite("1", 1, 1, F); // may fail
takeFile(F);
fwrite("1", 1, 1, F); // no warning
}
void check_escape3(void) {
FILE *F = tmpfile();
if (!F)
return;
takeFile(F);
F = freopen(0, "w", F);
if (!F)
return;
fwrite("1", 1, 1, F); // may fail
fwrite("1", 1, 1, F); // no warning
}
void check_escape4(void) {
FILE *F = tmpfile();
if (!F)
return;
fwrite("1", 1, 1, F); // may fail
// no escape at (non-StreamChecker-handled) system call
// FIXME: all such calls should be handled by the checker
fprintf(F, "0");
fwrite("1", 1, 1, F); // expected-warning {{might be 'indeterminate'}}
fclose(F);
}
int Test;
_Noreturn void handle_error(void);
void check_leak_noreturn_1(void) {
FILE *F1 = tmpfile();
if (!F1)
return;
if (Test == 1) {
handle_error(); // no warning
}
rewind(F1);
} // expected-warning {{Opened stream never closed. Potential resource leak}}
// Check that "location uniqueing" works.
// This results in reporting only one occurence of resource leak for a stream.
void check_leak_noreturn_2(void) {
FILE *F1 = tmpfile();
if (!F1)
return;
if (Test == 1) {
return; // no warning
}
rewind(F1);
} // expected-warning {{Opened stream never closed. Potential resource leak}}
// FIXME: This warning should be placed at the `return` above.
// See https://reviews.llvm.org/D83120 about details.