[PATCH] D75851: [Analyzer][StreamChecker] Added evaluation of fseek.
Balázs Kéri via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Mon Mar 9 09:08:52 PDT 2020
balazske created this revision.
Herald added subscribers: cfe-commits, martong, Charusso, gamesh411, dkrupp, donat.nagy, Szelethus, mikhail.ramalho, a.sidorin, szepet, baloghadamsoftware, xazax.hun.
Herald added a reviewer: Szelethus.
Herald added a project: clang.
balazske added a parent revision: D75682: [Analyzer][StreamChecker] Introduction of stream error handling..
Function `fseek` is now evaluated with setting error return value
and error flags.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D75851
Files:
clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
clang/test/Analysis/stream-error.c
Index: clang/test/Analysis/stream-error.c
===================================================================
--- clang/test/Analysis/stream-error.c
+++ clang/test/Analysis/stream-error.c
@@ -38,3 +38,20 @@
}
fclose(F);
}
+
+void error_fseek() {
+ FILE *F = fopen("file", "r");
+ if (!F)
+ return;
+ int rc = fseek(F, 0, SEEK_SET);
+ if (rc) {
+ int Eof = feof(F), Error = ferror(F);
+ clang_analyzer_eval(Eof || Error); // expected-warning {{FALSE}} \
+ // expected-warning {{TRUE}}
+ clang_analyzer_eval(Eof && Error); // expected-warning {{FALSE}}
+ } else {
+ clang_analyzer_eval(feof(F)); // expected-warning {{FALSE}}
+ clang_analyzer_eval(ferror(F)); // expected-warning {{FALSE}}
+ }
+ fclose(F);
+}
Index: clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -128,7 +128,7 @@
{&StreamChecker::preDefault, &StreamChecker::evalFclose, 0}},
{{"fread", 4}, {&StreamChecker::preDefault, nullptr, 3}},
{{"fwrite", 4}, {&StreamChecker::preDefault, nullptr, 3}},
- {{"fseek", 3}, {&StreamChecker::preFseek, nullptr, 0}},
+ {{"fseek", 3}, {&StreamChecker::preFseek, &StreamChecker::evalFseek, 0}},
{{"ftell", 1}, {&StreamChecker::preDefault, nullptr, 0}},
{{"rewind", 1}, {&StreamChecker::preDefault, nullptr, 0}},
{{"fgetpos", 2}, {&StreamChecker::preDefault, nullptr, 0}},
@@ -154,6 +154,8 @@
void preFseek(const FnDescription *Desc, const CallEvent &Call,
CheckerContext &C) const;
+ void evalFseek(const FnDescription *Desc, const CallEvent &Call,
+ CheckerContext &C) const;
void preDefault(const FnDescription *Desc, const CallEvent &Call,
CheckerContext &C) const;
@@ -340,6 +342,48 @@
C.addTransition(State);
}
+void StreamChecker::evalFseek(const FnDescription *Desc, const CallEvent &Call,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+ SymbolRef StreamSym = getStreamArg(Desc, Call).getAsSymbol();
+ if (!StreamSym)
+ return;
+
+ const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
+ if (!CE)
+ return;
+
+ // Ignore the call if the stream is not tracked.
+ if (!State->get<StreamMap>(StreamSym))
+ return;
+
+ DefinedSVal RetVal = makeRetVal(C, CE);
+
+ // Make expression result.
+ State = State->BindExpr(CE, C.getLocationContext(), RetVal);
+
+ // Bifurcate the state into failed and non-failed.
+ // Return zero on success, nonzero on error.
+ ProgramStateRef StateNotFailed, StateFailed;
+ std::tie(StateFailed, StateNotFailed) =
+ C.getConstraintManager().assumeDual(State, RetVal);
+
+ // Reset the state to opened with no error.
+ StateNotFailed =
+ StateNotFailed->set<StreamMap>(StreamSym, StreamState::getOpened());
+ // There are two ways of failure:
+ // We get some error (ferror or feof).
+ ProgramStateRef StateFailedWithFError = StateFailed->set<StreamMap>(
+ StreamSym, StreamState::getOpenedWithAnyError());
+ // We get none of the error flags.
+ ProgramStateRef StateFailedWithoutFError =
+ StateFailed->set<StreamMap>(StreamSym, StreamState::getOpened());
+
+ C.addTransition(StateNotFailed);
+ C.addTransition(StateFailedWithFError);
+ C.addTransition(StateFailedWithoutFError);
+}
+
void StreamChecker::evalClearerr(const FnDescription *Desc,
const CallEvent &Call,
CheckerContext &C) const {
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D75851.249118.patch
Type: text/x-patch
Size: 3698 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20200309/86f0cfc3/attachment-0001.bin>
More information about the cfe-commits
mailing list