[PATCH] D34275: [analyzer] Re-implemente current virtual calls checker in a path-sensitive way

Gábor Horváth via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Thu Jun 29 00:45:05 PDT 2017


xazax.hun added inline comments.


================
Comment at: lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp:31
+class VirtualCallChecker: public Checker<check::PreCall, check::PostCall> {
+  mutable std::unique_ptr<BugType> BT_CT;
+  mutable std::unique_ptr<BugType> BT_DT;
----------------
Could you find more descriptive names for these BugTypes?


================
Comment at: lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp:32
+  mutable std::unique_ptr<BugType> BT_CT;
+  mutable std::unique_ptr<BugType> BT_DT;
 
----------------
I'd rather have one bug type, describing a call to a virtual function from ctor/dtor. The actual error message can clarify whether this is a call from ctor or from dtor and whether it is pure virtual. You do not need to reflect every detail in the bug type. 


================
Comment at: lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp:35
 public:
-  WalkAST(const CheckerBase *checker, BugReporter &br, AnalysisDeclContext *ac,
-          const CXXMethodDecl *rootMethod, bool isInterprocedural,
-          bool reportPureOnly)
-      : Checker(checker), BR(br), AC(ac), RootMethod(rootMethod),
-        IsInterprocedural(isInterprocedural), ReportPureOnly(reportPureOnly),
-        visitingCallExpr(nullptr) {
-    // Walking should always start from either a constructor or a destructor.
-    assert(isa<CXXConstructorDecl>(rootMethod) ||
-           isa<CXXDestructorDecl>(rootMethod));
-  }
-
-  bool hasWork() const { return !WList.empty(); }
-
-  /// This method adds a CallExpr to the worklist and marks the callee as
-  /// being PreVisited.
-  void Enqueue(WorkListUnit WLUnit) {
-    const FunctionDecl *FD = WLUnit->getDirectCallee();
-    if (!FD || !FD->getBody())
-      return;
-    Kind &K = VisitedFunctions[FD];
-    if (K != NotVisited)
-      return;
-    K = PreVisited;
-    WList.push_back(WLUnit);
-  }
-
-  /// This method returns an item from the worklist without removing it.
-  WorkListUnit Dequeue() {
-    assert(!WList.empty());
-    return WList.back();
-  }
-
-  void Execute() {
-    while (hasWork()) {
-      WorkListUnit WLUnit = Dequeue();
-      const FunctionDecl *FD = WLUnit->getDirectCallee();
-      assert(FD && FD->getBody());
-
-      if (VisitedFunctions[FD] == PreVisited) {
-        // If the callee is PreVisited, walk its body.
-        // Visit the body.
-        SaveAndRestore<const CallExpr *> SaveCall(visitingCallExpr, WLUnit);
-        Visit(FD->getBody());
-
-        // Mark the function as being PostVisited to indicate we have
-        // scanned the body.
-        VisitedFunctions[FD] = PostVisited;
-        continue;
-      }
+  // The flag to determine if pure virtual functions should be issued only
+  DefaultBool isPureOnly;
----------------
Comments should be full sentences, this means they should be terminated with a period. 


================
Comment at: lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp:36
+  // The flag to determine if pure virtual functions should be issued only
+  DefaultBool isPureOnly;
 
----------------
Variables should start with capital letters. 


================
Comment at: lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp:40
+  void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
+  bool isCalledbyCtor(const CallExpr *CE,ProgramStateRef state,const LocationContext *LCtx) const;
+  bool isCalledbyDtor(const CallExpr *CE,ProgramStateRef state,const LocationContext *LCtx) const;
----------------
The names of the arguments should start with an uppercase letter. 


================
Comment at: lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp:72
+//GDM (generic data map) to determine if a function is called by an object
+REGISTER_TRAIT_WITH_PROGRAMSTATE(ObjectFlag, unsigned)
+//GDM (generic data map) to the memregion of this for the ctor and dtor
----------------
Do you need these traits above after having the maps bellow? 


================
Comment at: lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp:96
+ 
+  if((!CD && !DD) || (Ctorflag!=TrackedCtorDtorFlag && 
+      Dtorflag!=TrackedCtorDtorFlag)) 
----------------
The formatting here seems to be off, could you run clang-format on the code? This is a tool that can format the code to comply with the LLVM formatting style guide. 


================
Comment at: lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp:129
 
-void WalkAST::VisitChildren(Stmt *S) {
-  for (Stmt *Child : S->children())
-    if (Child)
-      Visit(Child);
-}
+  const auto *CC = dyn_cast_or_null<CXXConstructorCall>(&Call);
+  const auto *CD = dyn_cast_or_null<CXXDestructorCall>(&Call);
----------------
I think you do not need the or_null suffix here since the argument of this cast will never be null. 


================
Comment at: lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp:141
+  // Enter a constructor, increase the corresponding integer
+  if (dyn_cast<CXXConstructorDecl>(D)) {
+    unsigned Constructorflag = State->get<ConstructorFlag>();
----------------
If you do not use the result of `dyn_cast`, you could use `isa` instead. Even better, you could reuse `CC` or `DC` in this check. 


================
Comment at: lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp:168
     // this as a non-virtual call and do not warn.
-    if (CME->getQualifier())
-      callIsNonVirtual = true;
+    if (Expr *Base = CME->getBase()->IgnoreImpCasts()) {
+      if (!isa<CXXThisExpr>(Base)) {
----------------
Shouldn't this be const?


================
Comment at: lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp:192
+      }
+      else {
+      BT_CT.reset(new BugType(this, 
----------------
In LLVM we do not write the braces for conditionals that guarding a single statement. 


================
Comment at: lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp:218
+    }
+    ExplodedNode *N = C.generateNonFatalErrorNode();
+    auto Reporter = llvm::make_unique<BugReport>(*BT_DT, BT_DT->getName(), N);
----------------
In case of calling a pure virtual function maybe it would be better to stop the analysis, i.e.: creating a fatal error node.
Also, these functions might fail to give you back an ExplodedNode, so I think you should have a check here for that case. 


================
Comment at: lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp:314
+      return None;
+    const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(FD->getParent());
+    if (!MD)
----------------
Can getParent ever return null? Maybe you do not need the or_null suffix in the cast. 
Moreover are you sure that this method works? In case the function was a method, the parent should be the CXXRecordDecl, not a CXXMethodDecl. 



================
Comment at: lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp:332
+// Check the base of the callexpr is equal to the this of the ctor
+bool VirtualCallChecker::isCalledbyCtor(const CallExpr *CE,ProgramStateRef State,const LocationContext *LCtx) const {
+  if (const MemberExpr *CME = dyn_cast<MemberExpr>(CE->getCallee())) {
----------------
Maybe instead of callExpr, you should get CXXInstanceCall, which has a getCXXThisVal method. 


https://reviews.llvm.org/D34275





More information about the cfe-commits mailing list