balazske created this revision.
Herald added subscribers: cfe-commits, gamesh411, Szelethus, dkrupp.
Herald added a project: clang.
Recognization of function names is done now with the CallDescription
class instead of using IdentifierInfo. This means function name and
argument count is compared too.
A new check for filtering not global-C-functions was added.
Test was updated.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D67706
Files:
clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
clang/test/Analysis/stream.c
Index: clang/test/Analysis/stream.c
===================================================================
--- clang/test/Analysis/stream.c
+++ clang/test/Analysis/stream.c
@@ -1,6 +1,7 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.unix.Stream -analyzer-store region -verify %s
typedef __typeof__(sizeof(int)) size_t;
+typedef __typeof__(sizeof(int)) fpos_t;
typedef struct _IO_FILE FILE;
#define SEEK_SET 0 /* Seek from beginning of file. */
#define SEEK_CUR 1 /* Seek from current position. */
@@ -9,36 +10,93 @@
extern FILE *tmpfile(void);
extern int fclose(FILE *fp);
extern size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
+extern size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
extern int fseek (FILE *__stream, long int __off, int __whence);
extern long int ftell (FILE *__stream);
extern void rewind (FILE *__stream);
+extern int fgetpos(FILE *stream, fpos_t *pos);
+extern int fsetpos(FILE *stream, const fpos_t *pos);
+extern void clearerr(FILE *stream);
+extern int feof(FILE *stream);
+extern int ferror(FILE *stream);
+extern int fileno(FILE *stream);
-void f1(void) {
- FILE *p = fopen("foo", "r");
- char buf[1024];
- fread(buf, 1, 1, p); // expected-warning {{Stream pointer might be NULL}}
- fclose(p);
+void check_fread() {
+ FILE *fp = tmpfile();
+ fread(0, 0, 0, fp); // expected-warning {{Stream pointer might be NULL}}
+ fclose(fp);
}
-void f2(void) {
- FILE *p = fopen("foo", "r");
- fseek(p, 1, SEEK_SET); // expected-warning {{Stream pointer might be NULL}}
- fclose(p);
+void check_fwrite() {
+ FILE *fp = tmpfile();
+ fwrite(0, 0, 0, fp); // expected-warning {{Stream pointer might be NULL}}
+ fclose(fp);
}
-void f3(void) {
- FILE *p = fopen("foo", "r");
- ftell(p); // expected-warning {{Stream pointer might be NULL}}
- fclose(p);
+void check_fseek() {
+ FILE *fp = tmpfile();
+ fseek(fp, 0, 0); // expected-warning {{Stream pointer might be NULL}}
+ fclose(fp);
+}
+
+void check_ftell() {
+ FILE *fp = tmpfile();
+ ftell(fp); // expected-warning {{Stream pointer might be NULL}}
+ fclose(fp);
+}
+
+void check_rewind() {
+ FILE *fp = tmpfile();
+ rewind(fp); // expected-warning {{Stream pointer might be NULL}}
+ fclose(fp);
+}
+
+void check_fgetpos() {
+ FILE *fp = tmpfile();
+ fpos_t pos;
+ fgetpos(fp, &pos); // expected-warning {{Stream pointer might be NULL}}
+ fclose(fp);
+}
+
+void check_fsetpos() {
+ FILE *fp = tmpfile();
+ fpos_t pos;
+ fsetpos(fp, &pos); // expected-warning {{Stream pointer might be NULL}}
+ fclose(fp);
+}
+
+void check_clearerr() {
+ FILE *fp = tmpfile();
+ clearerr(fp); // expected-warning {{Stream pointer might be NULL}}
+ fclose(fp);
+}
+
+void check_feof() {
+ FILE *fp = tmpfile();
+ feof(fp); // expected-warning {{Stream pointer might be NULL}}
+ fclose(fp);
+}
+
+void check_ferror() {
+ FILE *fp = tmpfile();
+ ferror(fp); // expected-warning {{Stream pointer might be NULL}}
+ fclose(fp);
}
-void f4(void) {
+void check_fileno() {
+ FILE *fp = tmpfile();
+ fileno(fp); // expected-warning {{Stream pointer might be NULL}}
+ fclose(fp);
+}
+
+void f_open(void) {
FILE *p = fopen("foo", "r");
- rewind(p); // expected-warning {{Stream pointer might be NULL}}
+ char buf[1024];
+ fread(buf, 1, 1, p); // expected-warning {{Stream pointer might be NULL}}
fclose(p);
}
-void f5(void) {
+void f_seek(void) {
FILE *p = fopen("foo", "r");
if (!p)
return;
@@ -47,26 +105,20 @@
fclose(p);
}
-void f6(void) {
+void f_double_close(void) {
FILE *p = fopen("foo", "r");
fclose(p);
fclose(p); // expected-warning {{Try to close a file Descriptor already closed. Cause undefined behaviour}}
}
-void f7(void) {
- FILE *p = tmpfile();
- ftell(p); // expected-warning {{Stream pointer might be NULL}}
- fclose(p);
-}
-
-void f8(int c) {
+void f_leak(int c) {
FILE *p = fopen("foo.c", "r");
if(c)
return; // expected-warning {{Opened File never closed. Potential Resource leak}}
fclose(p);
}
-FILE *f9(void) {
+FILE *f_null_checked(void) {
FILE *p = fopen("foo.c", "r");
if (p)
return p; // no-warning
@@ -82,4 +134,3 @@
void pr8081(FILE *stream, long offset, int whence) {
fseek(stream, offset, whence);
}
-
Index: clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -57,20 +57,19 @@
class StreamChecker : public Checker<eval::Call,
check::DeadSymbols > {
- mutable IdentifierInfo *II_fopen, *II_tmpfile, *II_fclose, *II_fread,
- *II_fwrite,
- *II_fseek, *II_ftell, *II_rewind, *II_fgetpos, *II_fsetpos,
- *II_clearerr, *II_feof, *II_ferror, *II_fileno;
+ CallDescription CD_fopen, CD_tmpfile, CD_fclose, CD_fread, CD_fwrite,
+ CD_fseek, CD_ftell, CD_rewind, CD_fgetpos, CD_fsetpos, CD_clearerr,
+ CD_feof, CD_ferror, CD_fileno;
mutable std::unique_ptr<BuiltinBug> BT_nullfp, BT_illegalwhence,
BT_doubleclose, BT_ResourceLeak;
public:
StreamChecker()
- : II_fopen(nullptr), II_tmpfile(nullptr), II_fclose(nullptr),
- II_fread(nullptr), II_fwrite(nullptr), II_fseek(nullptr),
- II_ftell(nullptr), II_rewind(nullptr), II_fgetpos(nullptr),
- II_fsetpos(nullptr), II_clearerr(nullptr), II_feof(nullptr),
- II_ferror(nullptr), II_fileno(nullptr) {}
+ : CD_fopen("fopen"), CD_tmpfile("tmpfile"), CD_fclose("fclose", 1),
+ CD_fread("fread", 4), CD_fwrite("fwrite", 4), CD_fseek("fseek", 3),
+ CD_ftell("ftell", 1), CD_rewind("rewind", 1), CD_fgetpos("fgetpos", 2),
+ CD_fsetpos("fsetpos", 2), CD_clearerr("clearerr", 1),
+ CD_feof("feof", 1), CD_ferror("ferror", 1), CD_fileno("fileno", 1) {}
bool evalCall(const CallEvent &Call, CheckerContext &C) const;
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
@@ -105,6 +104,9 @@
bool StreamChecker::evalCall(const CallEvent &Call, CheckerContext &C) const {
+ if (!Call.isGlobalCFunction())
+ return false;
+
const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
if (!FD || FD->getKind() != Decl::Function)
return false;
@@ -113,89 +115,59 @@
if (!CE)
return false;
- ASTContext &Ctx = C.getASTContext();
- if (!II_fopen)
- II_fopen = &Ctx.Idents.get("fopen");
- if (!II_tmpfile)
- II_tmpfile = &Ctx.Idents.get("tmpfile");
- if (!II_fclose)
- II_fclose = &Ctx.Idents.get("fclose");
- if (!II_fread)
- II_fread = &Ctx.Idents.get("fread");
- if (!II_fwrite)
- II_fwrite = &Ctx.Idents.get("fwrite");
- if (!II_fseek)
- II_fseek = &Ctx.Idents.get("fseek");
- if (!II_ftell)
- II_ftell = &Ctx.Idents.get("ftell");
- if (!II_rewind)
- II_rewind = &Ctx.Idents.get("rewind");
- if (!II_fgetpos)
- II_fgetpos = &Ctx.Idents.get("fgetpos");
- if (!II_fsetpos)
- II_fsetpos = &Ctx.Idents.get("fsetpos");
- if (!II_clearerr)
- II_clearerr = &Ctx.Idents.get("clearerr");
- if (!II_feof)
- II_feof = &Ctx.Idents.get("feof");
- if (!II_ferror)
- II_ferror = &Ctx.Idents.get("ferror");
- if (!II_fileno)
- II_fileno = &Ctx.Idents.get("fileno");
-
- if (FD->getIdentifier() == II_fopen) {
+ if (Call.isCalled(CD_fopen)) {
Fopen(C, CE);
return true;
}
- if (FD->getIdentifier() == II_tmpfile) {
+ if (Call.isCalled(CD_tmpfile)) {
Tmpfile(C, CE);
return true;
}
- if (FD->getIdentifier() == II_fclose) {
+ if (Call.isCalled(CD_fclose)) {
Fclose(C, CE);
return true;
}
- if (FD->getIdentifier() == II_fread) {
+ if (Call.isCalled(CD_fread)) {
Fread(C, CE);
return true;
}
- if (FD->getIdentifier() == II_fwrite) {
+ if (Call.isCalled(CD_fwrite)) {
Fwrite(C, CE);
return true;
}
- if (FD->getIdentifier() == II_fseek) {
+ if (Call.isCalled(CD_fseek)) {
Fseek(C, CE);
return true;
}
- if (FD->getIdentifier() == II_ftell) {
+ if (Call.isCalled(CD_ftell)) {
Ftell(C, CE);
return true;
}
- if (FD->getIdentifier() == II_rewind) {
+ if (Call.isCalled(CD_rewind)) {
Rewind(C, CE);
return true;
}
- if (FD->getIdentifier() == II_fgetpos) {
+ if (Call.isCalled(CD_fgetpos)) {
Fgetpos(C, CE);
return true;
}
- if (FD->getIdentifier() == II_fsetpos) {
+ if (Call.isCalled(CD_fsetpos)) {
Fsetpos(C, CE);
return true;
}
- if (FD->getIdentifier() == II_clearerr) {
+ if (Call.isCalled(CD_clearerr)) {
Clearerr(C, CE);
return true;
}
- if (FD->getIdentifier() == II_feof) {
+ if (Call.isCalled(CD_feof)) {
Feof(C, CE);
return true;
}
- if (FD->getIdentifier() == II_ferror) {
+ if (Call.isCalled(CD_ferror)) {
Ferror(C, CE);
return true;
}
- if (FD->getIdentifier() == II_fileno) {
+ if (Call.isCalled(CD_fileno)) {
Fileno(C, CE);
return true;
}
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits