balazske updated this revision to Diff 249642.
balazske added a comment.
- Removed AnyError.
- Using common code for `evalFeof` and ferror.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D75682/new/
https://reviews.llvm.org/D75682
Files:
clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
Index: clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -19,7 +19,6 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
-#include <functional>
using namespace clang;
using namespace ento;
@@ -30,6 +29,7 @@
/// Full state information about a stream pointer.
struct StreamState {
/// State of a stream symbol.
+ /// FIXME: use a bool isOpened instead.
enum KindTy {
Opened, /// Stream is opened.
Closed, /// Closed stream (an invalid stream pointer after it was closed).
@@ -37,37 +37,44 @@
} State;
/// The error state of a stream.
+ /// Valid only if the stream is opened.
enum ErrorKindTy {
- NoError, /// No error flag is set or stream is not open.
- EofError, /// EOF condition (`feof` is true).
- OtherError, /// Other (non-EOF) error (`ferror` is true).
- AnyError /// EofError or OtherError, used if exact error is unknown.
+ /// No error flag is set (or stream is not open).
+ NoError,
+ /// EOF condition (`feof` is true).
+ FEof,
+ /// Other generic (non-EOF) error (`ferror` is true).
+ FError,
} ErrorState = NoError;
bool isOpened() const { return State == Opened; }
bool isClosed() const { return State == Closed; }
bool isOpenFailed() const { return State == OpenFailed; }
- bool isNoError() const { return ErrorState == NoError; }
- bool isEofError() const { return ErrorState == EofError; }
- bool isOtherError() const { return ErrorState == OtherError; }
- bool isAnyError() const { return ErrorState == AnyError; }
+ bool isNoError() const {
+ assert(State == Opened && "Error undefined for closed stream.");
+ return ErrorState == NoError;
+ }
+ bool isFEof() const {
+ assert(State == Opened && "Error undefined for closed stream.");
+ return ErrorState == FEof;
+ }
+ bool isFError() const {
+ assert(State == Opened && "Error undefined for closed stream.");
+ return ErrorState == FError;
+ }
bool operator==(const StreamState &X) const {
+ // In not opened state error should always NoError.
return State == X.State && ErrorState == X.ErrorState;
}
static StreamState getOpened() { return StreamState{Opened}; }
static StreamState getClosed() { return StreamState{Closed}; }
static StreamState getOpenFailed() { return StreamState{OpenFailed}; }
- static StreamState getOpenedWithAnyError() {
- return StreamState{Opened, AnyError};
- }
- static StreamState getOpenedWithEofError() {
- return StreamState{Opened, EofError};
- }
- static StreamState getOpenedWithOtherError() {
- return StreamState{Opened, OtherError};
+ static StreamState getOpenedWithFEof() { return StreamState{Opened, FEof}; }
+ static StreamState getOpenedWithFError() {
+ return StreamState{Opened, FError};
}
void Profile(llvm::FoldingSetNodeID &ID) const {
@@ -135,9 +142,12 @@
{{"fsetpos", 2}, {&StreamChecker::preDefault, nullptr, 0}},
{{"clearerr", 1},
{&StreamChecker::preDefault, &StreamChecker::evalClearerr, 0}},
- {{"feof", 1}, {&StreamChecker::preDefault, &StreamChecker::evalFeof, 0}},
+ {{"feof", 1},
+ {&StreamChecker::preDefault,
+ &StreamChecker::evalFeofFerror<&StreamState::isFEof>, 0}},
{{"ferror", 1},
- {&StreamChecker::preDefault, &StreamChecker::evalFerror, 0}},
+ {&StreamChecker::preDefault,
+ &StreamChecker::evalFeofFerror<&StreamState::isFError>, 0}},
{{"fileno", 1}, {&StreamChecker::preDefault, nullptr, 0}},
};
@@ -161,11 +171,9 @@
void evalClearerr(const FnDescription *Desc, const CallEvent &Call,
CheckerContext &C) const;
- void evalFeof(const FnDescription *Desc, const CallEvent &Call,
- CheckerContext &C) const;
-
- void evalFerror(const FnDescription *Desc, const CallEvent &Call,
- CheckerContext &C) const;
+ template <bool (StreamState::*IsOfError)() const>
+ void evalFeofFerror(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.
@@ -359,8 +367,10 @@
C.addTransition(State);
}
-void StreamChecker::evalFeof(const FnDescription *Desc, const CallEvent &Call,
- CheckerContext &C) const {
+template <bool (StreamState::*IsOfError)() const>
+void StreamChecker::evalFeofFerror(const FnDescription *Desc,
+ const CallEvent &Call,
+ CheckerContext &C) const {
ProgramStateRef State = C.getState();
SymbolRef StreamSym = getStreamArg(Desc, Call).getAsSymbol();
if (!StreamSym)
@@ -380,66 +390,10 @@
// Make expression result.
State = State->BindExpr(CE, C.getLocationContext(), RetVal);
- if (SS->isAnyError()) {
- // We do not know yet what kind of error is set.
- // Differentiate between EOF and other error.
- ProgramStateRef StateEof, StateOther;
- std::tie(StateEof, StateOther) = State->assume(RetVal);
- assert(StateEof && StateOther &&
- "Return value should not be constrained already.");
- StateEof = StateEof->set<StreamMap>(StreamSym,
- StreamState::getOpenedWithEofError());
- StateOther = StateOther->set<StreamMap>(
- StreamSym, StreamState::getOpenedWithOtherError());
- C.addTransition(StateEof);
- C.addTransition(StateOther);
- } else {
- // We know what error is set, make the return value accordingly.
- State = State->assume(RetVal, SS->isEofError());
- assert(State && "Return value should not be constrained already.");
- C.addTransition(State);
- }
-}
-
-void StreamChecker::evalFerror(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;
-
- const StreamState *SS = State->get<StreamMap>(StreamSym);
- // Ignore the call if the stream is not tracked.
- if (!SS)
- return;
-
- // Make expression result.
- DefinedSVal RetVal = makeRetVal(C, CE);
- State = State->BindExpr(CE, C.getLocationContext(), RetVal);
-
- if (SS->isAnyError()) {
- // We do not know yet what kind of error is set.
- // Differentiate between EOF and other error.
- ProgramStateRef StateEof, StateOther;
- std::tie(StateOther, StateEof) = State->assume(RetVal);
- assert(StateEof && StateOther &&
- "Return value should not be constrained already.");
- StateEof = StateEof->set<StreamMap>(StreamSym,
- StreamState::getOpenedWithEofError());
- StateOther = StateOther->set<StreamMap>(
- StreamSym, StreamState::getOpenedWithOtherError());
- C.addTransition(StateEof);
- C.addTransition(StateOther);
- } else {
- // We know what error is set, make the return value accordingly.
- State = State->assume(RetVal, SS->isOtherError());
- assert(State && "Return value should not be constrained already.");
- C.addTransition(State);
- }
+ // Make the return value accordingly to the error.
+ State = State->assume(RetVal, (SS->*IsOfError)());
+ assert(State && "Return value should not be constrained already.");
+ C.addTransition(State);
}
void StreamChecker::preDefault(const FnDescription *Desc, const CallEvent &Call,
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits