[cfe-commits] r159562 - in /cfe/trunk: include/clang/StaticAnalyzer/Core/Checker.h include/clang/StaticAnalyzer/Core/CheckerManager.h lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp lib/StaticAnalyzer/Core/CheckerManager.cpp lib/StaticAnalyzer/Core/ExprEngineCXX.cpp lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp lib/StaticAnalyzer/Core/ExprEngineObjC.cpp

Jordan Rose jordan_rose at apple.com
Mon Jul 2 12:28:16 PDT 2012


Author: jrose
Date: Mon Jul  2 14:28:16 2012
New Revision: 159562

URL: http://llvm.org/viewvc/llvm-project?rev=159562&view=rev
Log:
[analyzer] Add generic preCall and postCall checks.

Modified:
    cfe/trunk/include/clang/StaticAnalyzer/Core/Checker.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h
    cfe/trunk/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/Checker.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/Checker.h?rev=159562&r1=159561&r2=159562&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/Checker.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/Checker.h Mon Jul  2 14:28:16 2012
@@ -150,6 +150,36 @@
   }
 };
 
+class PreCall {
+  template <typename CHECKER>
+  static void _checkCall(void *checker, const CallEvent &msg,
+                         CheckerContext &C) {
+    ((const CHECKER *)checker)->checkPreCall(msg, C);
+  }
+
+public:
+  template <typename CHECKER>
+  static void _register(CHECKER *checker, CheckerManager &mgr) {
+    mgr._registerForPreCall(
+     CheckerManager::CheckCallFunc(checker, _checkCall<CHECKER>));
+  }
+};
+
+class PostCall {
+  template <typename CHECKER>
+  static void _checkCall(void *checker, const CallEvent &msg,
+                         CheckerContext &C) {
+    ((const CHECKER *)checker)->checkPostCall(msg, C);
+  }
+
+public:
+  template <typename CHECKER>
+  static void _register(CHECKER *checker, CheckerManager &mgr) {
+    mgr._registerForPostCall(
+     CheckerManager::CheckCallFunc(checker, _checkCall<CHECKER>));
+  }
+};
+
 class Location {
   template <typename CHECKER>
   static void _checkLocation(void *checker,
@@ -372,16 +402,14 @@
           typename CHECK11=check::_VoidCheck,typename CHECK12=check::_VoidCheck,
           typename CHECK13=check::_VoidCheck,typename CHECK14=check::_VoidCheck,
           typename CHECK15=check::_VoidCheck,typename CHECK16=check::_VoidCheck,
-          typename CHECK17=check::_VoidCheck,typename CHECK18=check::_VoidCheck>
+          typename CHECK17=check::_VoidCheck,typename CHECK18=check::_VoidCheck,
+          typename CHECK19=check::_VoidCheck,typename CHECK20=check::_VoidCheck,
+          typename CHECK21=check::_VoidCheck,typename CHECK22=check::_VoidCheck,
+          typename CHECK23=check::_VoidCheck,typename CHECK24=check::_VoidCheck>
 class Checker;
 
 template <>
-class Checker<check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
-                check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
-                check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
-                check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
-                check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
-                check::_VoidCheck, check::_VoidCheck, check::_VoidCheck>
+class Checker<check::_VoidCheck>
   : public CheckerBase 
 {
   virtual void anchor();
@@ -393,19 +421,22 @@
           typename CHECK5, typename CHECK6, typename CHECK7, typename CHECK8,
           typename CHECK9, typename CHECK10,typename CHECK11,typename CHECK12,
           typename CHECK13,typename CHECK14,typename CHECK15,typename CHECK16,
-          typename CHECK17,typename CHECK18>
+          typename CHECK17,typename CHECK18,typename CHECK19,typename CHECK20,
+          typename CHECK21,typename CHECK22,typename CHECK23,typename CHECK24>
 class Checker
     : public CHECK1,
-      public Checker<CHECK2, CHECK3, CHECK4, CHECK5, CHECK6, CHECK7, CHECK8,
-                     CHECK9, CHECK10,CHECK11,CHECK12,CHECK13,CHECK14,CHECK15,
-                     CHECK16,CHECK17,CHECK18> {
+      public Checker<CHECK2, CHECK3, CHECK4, CHECK5, CHECK6, CHECK7,
+                     CHECK8, CHECK9, CHECK10,CHECK11,CHECK12,CHECK13,
+                     CHECK14,CHECK15,CHECK16,CHECK17,CHECK18,CHECK19,
+                     CHECK20,CHECK21,CHECK22,CHECK23,CHECK24> {
 public:
   template <typename CHECKER>
   static void _register(CHECKER *checker, CheckerManager &mgr) {
     CHECK1::_register(checker, mgr);
-    Checker<CHECK2, CHECK3, CHECK4, CHECK5, CHECK6, CHECK7, CHECK8,
-            CHECK9, CHECK10,CHECK11,CHECK12,CHECK13,CHECK14,CHECK15,
-            CHECK16,CHECK17,CHECK18>::_register(checker, mgr);
+    Checker<CHECK2, CHECK3, CHECK4, CHECK5, CHECK6, CHECK7,
+            CHECK8, CHECK9, CHECK10,CHECK11,CHECK12,CHECK13,
+            CHECK14,CHECK15,CHECK16,CHECK17,CHECK18,CHECK19,
+            CHECK20,CHECK21,CHECK22,CHECK23,CHECK24>::_register(checker, mgr);
   }
 };
 

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h?rev=159562&r1=159561&r2=159562&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h Mon Jul  2 14:28:16 2012
@@ -221,6 +221,23 @@
                                  const ExplodedNodeSet &Src,
                                  const ObjCMethodCall &msg, ExprEngine &Eng);
 
+  /// \brief Run checkers for pre-visiting obj-c messages.
+  void runCheckersForPreCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src,
+                             const CallEvent &Call, ExprEngine &Eng) {
+    runCheckersForCallEvent(/*isPreVisit=*/true, Dst, Src, Call, Eng);
+  }
+
+  /// \brief Run checkers for post-visiting obj-c messages.
+  void runCheckersForPostCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src,
+                              const CallEvent &Call, ExprEngine &Eng) {
+    runCheckersForCallEvent(/*isPreVisit=*/false, Dst, Src, Call, Eng);
+  }
+
+  /// \brief Run checkers for visiting obj-c messages.
+  void runCheckersForCallEvent(bool isPreVisit, ExplodedNodeSet &Dst,
+                               const ExplodedNodeSet &Src,
+                               const CallEvent &Call, ExprEngine &Eng);
+
   /// \brief Run checkers for load/store of a location.
   void runCheckersForLocation(ExplodedNodeSet &Dst,
                               const ExplodedNodeSet &Src,
@@ -339,6 +356,9 @@
   
   typedef CheckerFn<void (const ObjCMethodCall &, CheckerContext &)>
       CheckObjCMessageFunc;
+
+  typedef CheckerFn<void (const CallEvent &, CheckerContext &)>
+      CheckCallFunc;
   
   typedef CheckerFn<void (const SVal &location, bool isLoad,
                           const Stmt *S,
@@ -397,6 +417,9 @@
   void _registerForPreObjCMessage(CheckObjCMessageFunc checkfn);
   void _registerForPostObjCMessage(CheckObjCMessageFunc checkfn);
 
+  void _registerForPreCall(CheckCallFunc checkfn);
+  void _registerForPostCall(CheckCallFunc checkfn);
+
   void _registerForLocation(CheckLocationFunc checkfn);
 
   void _registerForBind(CheckBindFunc checkfn);
@@ -518,6 +541,9 @@
   std::vector<CheckObjCMessageFunc> PreObjCMessageCheckers;
   std::vector<CheckObjCMessageFunc> PostObjCMessageCheckers;
 
+  std::vector<CheckCallFunc> PreCallCheckers;
+  std::vector<CheckCallFunc> PostCallCheckers;
+
   std::vector<CheckLocationFunc> LocationCheckers;
 
   std::vector<CheckBindFunc> BindCheckers;

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp?rev=159562&r1=159561&r2=159562&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp Mon Jul  2 14:28:16 2012
@@ -37,6 +37,8 @@
                                        check::PostStmt<CallExpr>,
                                        check::PreObjCMessage,
                                        check::PostObjCMessage,
+                                       check::PreCall,
+                                       check::PostCall,
                                        check::BranchCondition,
                                        check::Location,
                                        check::Bind,
@@ -72,15 +74,43 @@
   /// which does not include the control flow statements such as IfStmt. The
   /// callback can be specialized to be called with any subclass of Stmt.
   ///
-  /// check::PostStmt<DeclStmt>
+  /// check::PostStmt<CallExpr>
   void checkPostStmt(const CallExpr *DS, CheckerContext &C) const;
 
-  /// \brief Pre-visit the Objective C messages.
+  /// \brief Pre-visit the Objective C message.
+  ///
+  /// This will be called before the analyzer core processes the method call.
+  /// This is called for any action which produces an Objective-C message send,
+  /// including explicit message syntax and property access. See the subclasses
+  /// of ObjCMethodCall for more details.
+  ///
+  /// check::PreObjCMessage
   void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const {}
 
-  /// \brief Post-visit the Objective C messages.
+  /// \brief Post-visit the Objective C message.
+  /// \sa checkPreObjCMessage()
+  ///
+  /// check::PostObjCMessage
   void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const {}
 
+  /// \brief Pre-visit an abstract "call" event.
+  ///
+  /// This is used for checkers that want to check arguments or attributed
+  /// behavior for functions and methods no matter how they are being invoked.
+  ///
+  /// Note that this includes ALL cross-body invocations, so if you want to
+  /// limit your checks to, say, function calls, you can either test for that
+  /// or fall back to the explicit callback (i.e. check::PreStmt).
+  ///
+  /// check::PreCall
+  void checkPreCall(const CallEvent &Call, CheckerContext &C) const {}
+
+  /// \brief Post-visit an abstract "call" event.
+  /// \sa checkPreObjCMessage()
+  ///
+  /// check::PostCall
+  void checkPostCall(const CallEvent &Call, CheckerContext &C) const {}
+
   /// \brief Pre-visit of the condition statement of a branch (such as IfStmt).
   void checkBranchCondition(const Stmt *Condition, CheckerContext &Ctx) const {}
 

Modified: cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp?rev=159562&r1=159561&r2=159562&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp Mon Jul  2 14:28:16 2012
@@ -25,6 +25,8 @@
   return !StmtCheckers.empty()              ||
          !PreObjCMessageCheckers.empty()    ||
          !PostObjCMessageCheckers.empty()   ||
+         !PreCallCheckers.empty()    ||
+         !PostCallCheckers.empty()   ||
          !LocationCheckers.empty()          ||
          !BindCheckers.empty()              ||
          !EndAnalysisCheckers.empty()       ||
@@ -217,6 +219,54 @@
 }
 
 namespace {
+  // FIXME: This has all the same signatures as CheckObjCMessageContext.
+  // Is there a way we can merge the two?
+  struct CheckCallContext {
+    typedef std::vector<CheckerManager::CheckCallFunc> CheckersTy;
+    bool IsPreVisit;
+    const CheckersTy &Checkers;
+    const CallEvent &Call;
+    ExprEngine &Eng;
+
+    CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
+    CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
+
+    CheckCallContext(bool isPreVisit, const CheckersTy &checkers,
+                     const CallEvent &call, ExprEngine &eng)
+    : IsPreVisit(isPreVisit), Checkers(checkers), Call(call), Eng(eng) { }
+
+    void runChecker(CheckerManager::CheckCallFunc checkFn,
+                    NodeBuilder &Bldr, ExplodedNode *Pred) {
+      // FIXME: This will be wrong as soon as we handle any calls without
+      // associated statements.
+      ProgramPoint::Kind K = IsPreVisit ? ProgramPoint::PreStmtKind
+                                        : ProgramPoint::PostStmtKind;
+      assert(Call.getOriginExpr() && "Calls without stmts not yet handled");
+      const ProgramPoint &L =
+        ProgramPoint::getProgramPoint(Call.getOriginExpr(),
+                                      K, Pred->getLocationContext(),
+                                      checkFn.Checker);
+      CheckerContext C(Bldr, Eng, Pred, L);
+
+      checkFn(Call, C);
+    }
+  };
+}
+
+/// \brief Run checkers for visiting an abstract call event.
+void CheckerManager::runCheckersForCallEvent(bool isPreVisit,
+                                             ExplodedNodeSet &Dst,
+                                             const ExplodedNodeSet &Src,
+                                             const CallEvent &Call,
+                                             ExprEngine &Eng) {
+  CheckCallContext C(isPreVisit,
+                     isPreVisit ? PreCallCheckers
+                                : PostCallCheckers,
+                     Call, Eng);
+  expandGraphWithCheckers(C, Dst, Src);
+}
+
+namespace {
   struct CheckLocationContext {
     typedef std::vector<CheckerManager::CheckLocationFunc> CheckersTy;
     const CheckersTy &Checkers;
@@ -584,6 +634,13 @@
   PostObjCMessageCheckers.push_back(checkfn);
 }
 
+void CheckerManager::_registerForPreCall(CheckCallFunc checkfn) {
+  PreCallCheckers.push_back(checkfn);
+}
+void CheckerManager::_registerForPostCall(CheckCallFunc checkfn) {
+  PostCallCheckers.push_back(checkfn);
+}
+
 void CheckerManager::_registerForLocation(CheckLocationFunc checkfn) {
   LocationCheckers.push_back(checkfn);
 }

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp?rev=159562&r1=159561&r2=159562&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Mon Jul  2 14:28:16 2012
@@ -55,14 +55,19 @@
 
   ExplodedNodeSet DstPreVisit;
   getCheckerManager().runCheckersForPreStmt(DstPreVisit, Pred, CE, *this);
+  ExplodedNodeSet DstPreCall;
+  getCheckerManager().runCheckersForPreCall(DstPreCall, DstPreVisit,
+                                            Call, *this);
 
   ExplodedNodeSet DstInvalidated;
-  for (ExplodedNodeSet::iterator I = DstPreVisit.begin(), E = DstPreVisit.end();
+  for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
        I != E; ++I)
     defaultEvalCall(DstInvalidated, *I, Call);
 
-  getCheckerManager().runCheckersForPostStmt(destNodes, DstInvalidated,
-                                             CE, *this);
+  ExplodedNodeSet DstPostCall;
+  getCheckerManager().runCheckersForPostCall(DstPostCall, DstInvalidated,
+                                             Call, *this);
+  getCheckerManager().runCheckersForPostStmt(destNodes, DstPostCall, CE, *this);
 }
 
 void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD,

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp?rev=159562&r1=159561&r2=159562&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp Mon Jul  2 14:28:16 2012
@@ -359,7 +359,20 @@
 
 void ExprEngine::evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
                           const SimpleCall &Call) {
-  getCheckerManager().runCheckersForEvalCall(Dst, Pred, Call, *this);
+  // Run any pre-call checks using the generic call interface.
+  ExplodedNodeSet dstPreVisit;
+  getCheckerManager().runCheckersForPreCall(dstPreVisit, Pred, Call, *this);
+
+  // Actually evaluate the function call.  We try each of the checkers
+  // to see if the can evaluate the function call, and get a callback at
+  // defaultEvalCall if all of them fail.
+  ExplodedNodeSet dstCallEvaluated;
+  getCheckerManager().runCheckersForEvalCall(dstCallEvaluated, dstPreVisit,
+                                             Call, *this);
+
+  // Finally, run any post-call checks.
+  getCheckerManager().runCheckersForPostCall(Dst, dstCallEvaluated,
+                                             Call, *this);
 }
 
 void ExprEngine::defaultEvalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp?rev=159562&r1=159561&r2=159562&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp Mon Jul  2 14:28:16 2012
@@ -146,15 +146,18 @@
   
   // Handle the previsits checks.
   ExplodedNodeSet dstPrevisit;
-  getCheckerManager().runCheckersForPreObjCMessage(dstPrevisit, Pred, 
+  getCheckerManager().runCheckersForPreObjCMessage(dstPrevisit, Pred,
                                                    msg, *this);
-  
+  ExplodedNodeSet dstGenericPrevisit;
+  getCheckerManager().runCheckersForPreCall(dstGenericPrevisit, dstPrevisit,
+                                            msg, *this);
+
   // Proceed with evaluate the message expression.
   ExplodedNodeSet dstEval;
-  StmtNodeBuilder Bldr(dstPrevisit, dstEval, *currentBuilderContext);
+  StmtNodeBuilder Bldr(dstGenericPrevisit, dstEval, *currentBuilderContext);
 
-  for (ExplodedNodeSet::iterator DI = dstPrevisit.begin(),
-       DE = dstPrevisit.end(); DI != DE; ++DI) {
+  for (ExplodedNodeSet::iterator DI = dstGenericPrevisit.begin(),
+       DE = dstGenericPrevisit.end(); DI != DE; ++DI) {
     
     ExplodedNode *Pred = *DI;
     bool RaisesException = false;
@@ -235,9 +238,13 @@
     }
   }
   
+  ExplodedNodeSet dstPostvisit;
+  getCheckerManager().runCheckersForPostCall(dstPostvisit, dstEval, msg, *this);
+
   // Finally, perform the post-condition check of the ObjCMessageExpr and store
   // the created nodes in 'Dst'.
-  getCheckerManager().runCheckersForPostObjCMessage(Dst, dstEval, msg, *this);
+  getCheckerManager().runCheckersForPostObjCMessage(Dst, dstPostvisit,
+                                                    msg, *this);
 }
 
 void ExprEngine::evalObjCMessage(StmtNodeBuilder &Bldr,
@@ -280,7 +287,7 @@
   state = msg.invalidateRegions(BlockCount, state);
 
   // And create the new node.
-  Bldr.generateNode(msg.getOriginExpr(), Pred, state, GenSink);
+  Bldr.generateNode(currentStmt, Pred, state, GenSink);
   assert(Bldr.hasGeneratedNodes());
 }
 





More information about the cfe-commits mailing list