[clang] [clang][analyzer] Support `fflush` in the StreamChecker (PR #74296)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Dec 4 01:49:53 PST 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-static-analyzer-1
@llvm/pr-subscribers-clang
Author: Ben Shi (benshi001)
<details>
<summary>Changes</summary>
---
Full diff: https://github.com/llvm/llvm-project/pull/74296.diff
3 Files Affected:
- (modified) clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp (+16)
- (modified) clang/test/Analysis/Inputs/system-header-simulator.h (+1)
- (modified) clang/test/Analysis/stream-error.c (+9)
``````````diff
diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index a4799b5f762ca..5744feba4d35b 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -266,6 +266,7 @@ class StreamChecker : public Checker<check::PreCall, eval::Call,
{&StreamChecker::preFseek, &StreamChecker::evalFseek, 0}},
{{{"ftell"}, 1},
{&StreamChecker::preDefault, &StreamChecker::evalFtell, 0}},
+ {{{"fflush"}, 1}, {&StreamChecker::preFflush, nullptr, 0}},
{{{"rewind"}, 1},
{&StreamChecker::preDefault, &StreamChecker::evalRewind, 0}},
{{{"fgetpos"}, 2},
@@ -360,6 +361,9 @@ class StreamChecker : public Checker<check::PreCall, eval::Call,
CheckerContext &C,
const StreamErrorState &ErrorKind) const;
+ void preFflush(const FnDescription *Desc, const CallEvent &Call,
+ CheckerContext &C) const;
+
/// Check that the stream (in StreamVal) is not NULL.
/// If it can only be NULL a fatal error is emitted and nullptr returned.
/// Otherwise the return value is a new state where the stream is constrained
@@ -1188,6 +1192,18 @@ void StreamChecker::evalSetFeofFerror(const FnDescription *Desc,
C.addTransition(State);
}
+void StreamChecker::preFflush(const FnDescription *Desc, const CallEvent &Call,
+ CheckerContext &C) const {
+ // Skip if the stream is NULL/nullptr, which means flush all streams.
+ if (!Call.getArgExpr(Desc->StreamArgNo)
+ ->isNullPointerConstant(C.getASTContext(),
+ Expr::NPC_ValueDependentIsNotNull)) {
+ ProgramStateRef State = C.getState();
+ if (State = ensureStreamOpened(getStreamArg(Desc, Call), C, State))
+ C.addTransition(State);
+ }
+}
+
ProgramStateRef
StreamChecker::ensureStreamNonNull(SVal StreamVal, const Expr *StreamE,
CheckerContext &C,
diff --git a/clang/test/Analysis/Inputs/system-header-simulator.h b/clang/test/Analysis/Inputs/system-header-simulator.h
index 7089bd8bfc9d9..409a969a0d4cc 100644
--- a/clang/test/Analysis/Inputs/system-header-simulator.h
+++ b/clang/test/Analysis/Inputs/system-header-simulator.h
@@ -61,6 +61,7 @@ void clearerr(FILE *stream);
int feof(FILE *stream);
int ferror(FILE *stream);
int fileno(FILE *stream);
+int fflush(FILE *stream);
size_t strlen(const char *);
diff --git a/clang/test/Analysis/stream-error.c b/clang/test/Analysis/stream-error.c
index c8332bcbfa8ca..aa5b6be851773 100644
--- a/clang/test/Analysis/stream-error.c
+++ b/clang/test/Analysis/stream-error.c
@@ -299,6 +299,15 @@ void error_fseek_0(void) {
fclose(F);
}
+void error_fflush(void) {
+ FILE *F = tmpfile();
+ if (!F)
+ return;
+ fclose(F);
+ fflush(F); // expected-warning {{Stream might be already closed}}
+ fflush(NULL); // no-warning
+}
+
void error_indeterminate(void) {
FILE *F = fopen("file", "r+");
if (!F)
``````````
</details>
https://github.com/llvm/llvm-project/pull/74296
More information about the cfe-commits
mailing list