[PATCH] D67706: [clang][analyzer] Using CallDescription in StreamChecker.

Balázs Kéri via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 30 08:24:53 PDT 2019


balazske marked 22 inline comments as done and an inline comment as not done.
balazske added inline comments.


================
Comment at: clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp:90-106
+  FnCheck identifyCall(const CallEvent &Call, CheckerContext &C,
+                       const CallExpr *CE) const;
+
+  void evalFopen(CheckerContext &C, const CallExpr *CE) const;
+  void evalTmpfile(CheckerContext &C, const CallExpr *CE) const;
+  void evalFclose(CheckerContext &C, const CallExpr *CE) const;
+  void evalFread(CheckerContext &C, const CallExpr *CE) const;
----------------
NoQ wrote:
> balazske wrote:
> > NoQ wrote:
> > > For most purposes it's more convenient to pass `CallEvent` around. The only moment when you actually need the `CallExpr` is when you're doing the binding for the return value, which happens once, so it's fine to call `.getOriginExpr()` directly at this point.
> > The CallExpr is used at many places to get arguments and other data. There is a `CallEvent::getArgSVal` that can be used instead but at some places CallExpr is used in other ways. I do not see much benefit of change the passed `CallExpr` to `CallEvent`.
> > at some places CallExpr is used in other ways
> 
> Can we add more convenient getters to `CallEvent` to help with those? 'Cause `CallEvent` has strictly more information than `CallExpr` (combining syntactic information with path-sensitive information), it's all about convenience.
> 
> I also see that `CallExpr` is stored in `StreamState` (which is something you can't do with a `CallEvent` because it's short-lived) but i suspect that it's actually never read from there and i doubt that it was the right solution anyway. I.e., no other checker needs that and i don't have a reason to believe that `StreamChecker` is special.
In the new code `CallEvent` is passed.


================
Comment at: clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp:61
+  using FnCheck = bool (StreamChecker::*)(const CallEvent &,
+                                          CheckerContext &) const;
+
----------------
Szelethus wrote:
> Charusso wrote:
> > I prefer `std::function`, because it is modern.
> > ```
> >   using StreamCheck = 
> >       std::function<void(const StreamChecker *, const CallEvent &,
> >                          CheckerContext &)>;
> > ```
> > I think it is fine with pointers, but at some point we need to modernize this.
> But its also a lot more expensive. https://blog.demofox.org/2015/02/25/avoiding-the-performance-hazzards-of-stdfunction/
> 
> `std::function` is able to wrap lambdas with different captures and all sorts of things like that, which comes at a cost.
Now `std::function` and `std::bind` is used. Probably more expensive but it is called once in a `evalCall`, that should be no problem?


================
Comment at: clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp:99
+  Optional<ProgramStateRef> CheckNullStream(SVal SV, CheckerContext &C) const;
+  Optional<ProgramStateRef> CheckDoubleClose(const CallEvent &Call,
+                                             CheckerContext &C) const;
----------------
Charusso wrote:
> This `Optional` is not necessary. When the state is changed, you can rely on `CheckerContext::isDifferent()` to see whether the modeling was succeeded. Therefore you could revert the `bool` return values as well.
`Optional` is not used now. The functions only return if the passed state was modified (if applicable). To detect if error was generated the `isDifferent` is used.


================
Comment at: clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp:137
+  return *Callback;
 }
 
----------------
Charusso wrote:
> I would move this tiny `identifyCall()` into `evalCall()` as the purpose of `evalCall()` is the validation of the `Callback` in this case.
`identifyCall` is removed now.


================
Comment at: clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp:196
 
   if (ExplodedNode *N = C.generateNonFatalErrorNode(state)) {
     if (!BT_illegalwhence)
----------------
NoQ wrote:
> This is getting pretty messy, given that you've already made a transition in this function. If you do `addTransition` and then `generateNonFatalErrorNode`, then you'll get two parallel successor nodes, but you only need one. You should either delay the transition that happens immediately after `CheckNullStream`, or chain the two transitions together sequentially (as opposed to in parallel).
`evalFseek` has now a transition to new (non-null stream) state or transition to (non-fatal) error.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D67706





More information about the cfe-commits mailing list