[PATCH] D75163: [analyzer][StreamChecker] Adding precall and refactoring.

Kristóf Umann via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Thu Feb 27 05:12:48 PST 2020


Szelethus added a comment.

To summarize, we're moving every stream check (illegal call to a stream management function with a null stream, or a closed stream, etc) to `preCall`, and leave only the modeling portions in `evalCall`. Makes sense!

You did an amazing job here! I like the new infrastructure and everything.



================
Comment at: clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp:76-92
+      {{"fopen"}, {{}, &StreamChecker::evalFopen, ArgNone}},
+      {{"freopen", 3},
+       {&StreamChecker::preFreopen, &StreamChecker::evalFreopen, 2}},
+      {{"tmpfile"}, {{}, &StreamChecker::evalFopen, ArgNone}},
+      {{"fclose", 1},
+       {&StreamChecker::preDefault, &StreamChecker::evalFclose, 0}},
+      {{"fread", 4}, {&StreamChecker::preDefault, {}, 3}},
----------------
Hmm, all of these braces are kinda hard to navigate, but its not too bad. Could you check whether changing them to `nullptr` improves readability? I'll leave it to your judgement.


================
Comment at: clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp:109-114
+  ProgramStateRef ensureStreamNonNull(SVal StreamVal, CheckerContext &C,
+                                      ProgramStateRef State) const;
+  ProgramStateRef ensureFseekWhenceCorrect(SVal WhenceVal, CheckerContext &C,
+                                           ProgramStateRef State) const;
+  ProgramStateRef ensureStreamOpened(SVal StreamVal, CheckerContext &C,
+                                     ProgramStateRef State) const;
----------------
Could we add/move some comments for these? :)

```
Checks whether the stream is non-null. If it is null, an fatal bug report is emitted and the return value is nullptr. Otherwise in the returned state StreamVal is non-null.
```


================
Comment at: clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp:161
+  ProgramStateRef State = C.getState();
+  SVal StreamVal = Call.getArgSVal(Desc->StreamArgNo);
+  State = ensureStreamNonNull(StreamVal, C, State);
----------------
This would assert in `Expr::getArg` if `Desc->StreamArgNo == ArgNone`, but that shouldn't ever happen in this function, correct? Could we add an assert here as well as a poor man's documentation?


================
Comment at: clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp:192-194
+  // Do not allow NULL as passed stream pointer.
+  // This is not specified in the man page but may crash on some system.
+  // But allow a closed stream, is this correct?
----------------
According to my research, yes, closed streams are okay. Also, the rest of the comment can be removed as well -- it is for sure not okay to pass `NULL` to `freopen`, even if it doesn't crash on some systems.


================
Comment at: clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp:281-284
+  // Close the File Descriptor.
+  // Regardless if the close fails or not, stream becomes "closed"
+  // and can not be used any more.
+  State = State->set<StreamMap>(Sym, StreamState::getClosed());
----------------
Ah, we're moving the closing of the stream from `checkDoubleClose` to here. Makes much more sense!


================
Comment at: clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp:341-345
+// Check:
+// Using a stream pointer after 'fclose' causes undefined behavior
+// according to cppreference.com .
+// Using a stream that has failed to open is likely to cause problems, but not
+// explicitly mentioned in documentation.
----------------
Could we move this to the declaration and start it with `///`?


================
Comment at: clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp:349-355
+  SymbolRef Sym = StreamVal.getAsSymbol();
   if (!Sym)
-    return State;
+    return nullptr;
 
   const StreamState *SS = State->get<StreamMap>(Sym);
-
-  // If the file stream is not tracked, return.
   if (!SS)
+    return nullptr;
----------------
Previously, we only returned a `nullptr` after generating a fatal error node. Why do we need to change this?


================
Comment at: clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp:363-364
+            new BuiltinBug(this, "Stream used after close",
+                           "File descriptor is used after it was closed. "
+                           "Cause undefined behaviour."));
       C.emitReport(std::make_unique<PathSensitiveBugReport>(
----------------
How about

"Closing an already closed file descriptor."


================
Comment at: clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp:381-382
+            new BuiltinBug(this, "Stream used after failed open",
+                           "(Re-)Opening the file descriptor has failed. "
+                           "Using it can cause undefined behaviour."));
+      C.emitReport(std::make_unique<PathSensitiveBugReport>(
----------------
How about

"Using a file descriptor after (re-)opening it failed."


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75163/new/

https://reviews.llvm.org/D75163





More information about the cfe-commits mailing list