[PATCH] D75851: [Analyzer][StreamChecker] Added evaluation of fseek.
Kristóf Umann via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Wed Apr 8 05:55:35 PDT 2020
Szelethus marked an inline comment as done.
Szelethus added a comment.
In D75851#1933538 <https://reviews.llvm.org/D75851#1933538>, @balazske wrote:
> Simplified code.
I can tell! The patch is amazing, the code practically reads itself aloud. I have some inlines but nothing major, the high level idea is great.
================
Comment at: clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp:103-110
+ /// Return if the specified error kind is possible on the stream in the
+ /// current state.
+ /// This depends on the stored `LastOperation` value.
+ /// If the error is not possible returns empty value.
+ /// If the error is possible returns the remaining possible error type
+ /// (after taking out `ErrorKind`). If a single error is possible it will
+ /// return that value, otherwise unknown error.
----------------
This feels clunky to me.
Suppose that we're curious about the stream reaching `EOF`. We know that the last operation on the stream could cause `EOF` and `ERROR`. This function then would return `FError`. That doesn't really feel like the answer to the question "isErrorPossible".
In what contexts do you see calling this function that isn't like this?:
```lang=c++
Optional<StreamState::ErrorKindTy> NewError =
SS->isErrorPossible(ErrorKind);
if (!NewError) {
// This kind of error is not possible, function returns zero.
// Error state remains unknown.
AddTransition(bindInt(0, State, C, CE), StreamState::UnknownError);
} else {
// Add state with true returned.
AddTransition(bindAndAssumeTrue(State, C, CE), ErrorKind);
// Add state with false returned and the new remaining error type.
AddTransition(bindInt(0, State, C, CE), *NewError);
}
```
Would it make more sense to move the logic of creating state transitions into a function instead?
================
Comment at: clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp:518
- if ((SS->*IsOfError)()) {
- // Function returns nonzero.
- DefinedSVal RetVal = makeRetVal(C, CE);
- State = State->BindExpr(CE, C.getLocationContext(), RetVal);
- State = State->assume(RetVal, true);
- assert(State && "Assumption on new value should not fail.");
+ if (!SS->isUnknownError()) {
+ // We know exactly what the error is.
----------------
It took me a while to realize that this also includes the case where the stat is not in any error :) Could you add a line of comment please?
================
Comment at: clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp:534-537
+ // Add state with true returned.
+ AddTransition(bindAndAssumeTrue(State, C, CE), ErrorKind);
+ // Add state with false returned and the new remaining error type.
+ AddTransition(bindInt(0, State, C, CE), *NewError);
----------------
I gave this plenty of thought, and I now believe that the state split here is appropriate. We really should ensure that the user checked both `feof` and `ferror`.
================
Comment at: clang/test/Analysis/stream-error.c:48
+ if (rc) {
+ int Eof = feof(F), Error = ferror(F);
+ // Get feof or ferror or no error.
----------------
That is a bit misleading, because `Eof` isn't `EOF` as specified in the standard. How about `IsEof`?
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D75851/new/
https://reviews.llvm.org/D75851
More information about the cfe-commits
mailing list