[cfe-commits] r160986 - in /cfe/trunk: include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp lib/StaticAnalyzer/Core/CallEvent.cpp lib/StaticAnalyzer/Core/CheckerManager.cpp lib/StaticAnalyzer/Core/ExprEngine.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 30 13:22:09 PDT 2012


Author: jrose
Date: Mon Jul 30 15:22:09 2012
New Revision: 160986

URL: http://llvm.org/viewvc/llvm-project?rev=160986&view=rev
Log:
[analyzer] Only allow CallEvents to be created by CallEventManager.

This ensures that it is valid to reference-count any CallEvents, and we
won't accidentally try to reclaim a CallEvent that lives on the stack.
It also hides an ugly switch statement for handling CallExprs!

There should be no functionality change here.

Modified:
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
    cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.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/PathSensitive/CallEvent.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h?rev=160986&r1=160985&r2=160986&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h Mon Jul 30 15:22:09 2012
@@ -48,8 +48,18 @@
 };
 
 class CallEvent;
-typedef IntrusiveRefCntPtr<CallEvent> CallEventRef;
+class CallEventManager;
 
+template<typename T = CallEvent>
+class CallEventRef : public IntrusiveRefCntPtr<const T> {
+public:
+  CallEventRef(const T *Call) : IntrusiveRefCntPtr<const T>(Call) {}
+  CallEventRef(const CallEventRef &Orig) : IntrusiveRefCntPtr<const T>(Orig) {}
+
+  CallEventRef<T> cloneWithState(ProgramStateRef State) const {
+    return this->getPtr()->template cloneWithState<T>(State);
+  }
+};
 
 /// \brief Represents an abstract call to a function or method along a
 /// particular path.
@@ -89,6 +99,8 @@
   void Release() const;
 
 protected:
+  friend class CallEventManager;
+
   CallEvent(const Expr *E, ProgramStateRef state, const LocationContext *lctx)
     : State(state), LCtx(lctx), Origin(E), RefCount(0) {}
 
@@ -100,6 +112,7 @@
     : State(Original.State), LCtx(Original.LCtx), Origin(Original.Origin),
       Data(Original.Data), Location(Original.Location), RefCount(0) {}
 
+
   ProgramStateRef getState() const {
     return State;
   }
@@ -229,10 +242,10 @@
 
   /// Returns a copy of this CallEvent, but using the given state.
   template <typename T>
-  IntrusiveRefCntPtr<T> cloneWithState(ProgramStateRef NewState) const;
+  CallEventRef<T> cloneWithState(ProgramStateRef NewState) const;
 
   /// Returns a copy of this CallEvent, but using the given state.
-  CallEventRef cloneWithState(ProgramStateRef NewState) const {
+  CallEventRef<> cloneWithState(ProgramStateRef NewState) const {
     return cloneWithState<CallEvent>(NewState);
   }
 
@@ -364,15 +377,17 @@
 ///
 /// Example: \c fun()
 class FunctionCall : public SimpleCall {
-protected:
-  FunctionCall(const FunctionCall &Other) : SimpleCall(Other) {}
-  virtual void cloneTo(void *Dest) const { new (Dest) FunctionCall(*this); }
+  friend class CallEventManager;
 
-public:
+protected:
   FunctionCall(const CallExpr *CE, ProgramStateRef St,
                const LocationContext *LCtx)
     : SimpleCall(CE, St, LCtx) {}
 
+  FunctionCall(const FunctionCall &Other) : SimpleCall(Other) {}
+  virtual void cloneTo(void *Dest) const { new (Dest) FunctionCall(*this); }
+
+public:
   virtual Kind getKind() const { return CE_Function; }
 
   static bool classof(const CallEvent *CA) {
@@ -405,15 +420,17 @@
 ///
 /// Example: \c obj.fun()
 class CXXMemberCall : public CXXInstanceCall {
-protected:
-  CXXMemberCall(const CXXMemberCall &Other) : CXXInstanceCall(Other) {}
-  virtual void cloneTo(void *Dest) const { new (Dest) CXXMemberCall(*this); }
+  friend class CallEventManager;
 
-public:
+protected:
   CXXMemberCall(const CXXMemberCallExpr *CE, ProgramStateRef St,
                 const LocationContext *LCtx)
     : CXXInstanceCall(CE, St, LCtx) {}
 
+  CXXMemberCall(const CXXMemberCall &Other) : CXXInstanceCall(Other) {}
+  virtual void cloneTo(void *Dest) const { new (Dest) CXXMemberCall(*this); }
+
+public:
   virtual const CXXMemberCallExpr *getOriginExpr() const {
     return cast<CXXMemberCallExpr>(SimpleCall::getOriginExpr());
   }
@@ -432,7 +449,13 @@
 ///
 /// Example: <tt>iter + 1</tt>
 class CXXMemberOperatorCall : public CXXInstanceCall {
+  friend class CallEventManager;
+
 protected:
+  CXXMemberOperatorCall(const CXXOperatorCallExpr *CE, ProgramStateRef St,
+                        const LocationContext *LCtx)
+    : CXXInstanceCall(CE, St, LCtx) {}
+
   CXXMemberOperatorCall(const CXXMemberOperatorCall &Other)
     : CXXInstanceCall(Other) {}
   virtual void cloneTo(void *Dest) const {
@@ -440,10 +463,6 @@
   }
 
 public:
-  CXXMemberOperatorCall(const CXXOperatorCallExpr *CE, ProgramStateRef St,
-                        const LocationContext *LCtx)
-    : CXXInstanceCall(CE, St, LCtx) {}
-
   virtual const CXXOperatorCallExpr *getOriginExpr() const {
     return cast<CXXOperatorCallExpr>(SimpleCall::getOriginExpr());
   }
@@ -468,7 +487,13 @@
 ///
 /// Example: <tt>^{ /* ... */ }()</tt>
 class BlockCall : public SimpleCall {
+  friend class CallEventManager;
+
 protected:
+  BlockCall(const CallExpr *CE, ProgramStateRef St,
+            const LocationContext *LCtx)
+    : SimpleCall(CE, St, LCtx) {}
+
   BlockCall(const BlockCall &Other) : SimpleCall(Other) {}
   virtual void cloneTo(void *Dest) const { new (Dest) BlockCall(*this); }
 
@@ -477,10 +502,6 @@
   virtual QualType getDeclaredResultType() const;
 
 public:
-  BlockCall(const CallExpr *CE, ProgramStateRef St,
-            const LocationContext *LCtx)
-    : SimpleCall(CE, St, LCtx) {}
-
   /// \brief Returns the region associated with this instance of the block.
   ///
   /// This may be NULL if the block's origin is unknown.
@@ -515,27 +536,28 @@
 ///
 /// Example: \c T(1)
 class CXXConstructorCall : public AnyFunctionCall {
-protected:
-  CXXConstructorCall(const CXXConstructorCall &Other) : AnyFunctionCall(Other){}
-  virtual void cloneTo(void *Dest) const { new (Dest) CXXConstructorCall(*this); }
-
-  virtual void getExtraInvalidatedRegions(RegionList &Regions) const;
-
-public:
-  /// Represents a constructor call to a new or unknown region.
-  CXXConstructorCall(const CXXConstructExpr *CE, ProgramStateRef St,
-                     const LocationContext *LCtx)
-    : AnyFunctionCall(CE, St, LCtx) {
-    Data = 0;
-  }
+  friend class CallEventManager;
 
-  /// Represents a constructor call on an existing object region.
+protected:
+  /// Creates a constructor call.
+  ///
+  /// \param CE The constructor expression as written in the source.
+  /// \param Target The region where the object should be constructed. If NULL,
+  ///               a new symbolic region will be used.
+  /// \param St The path-sensitive state at this point in the program.
+  /// \param LCtx The location context at this point in the program.
   CXXConstructorCall(const CXXConstructExpr *CE, const MemRegion *target,
                      ProgramStateRef St, const LocationContext *LCtx)
     : AnyFunctionCall(CE, St, LCtx) {
     Data = target;
   }
 
+  CXXConstructorCall(const CXXConstructorCall &Other) : AnyFunctionCall(Other){}
+  virtual void cloneTo(void *Dest) const { new (Dest) CXXConstructorCall(*this); }
+
+  virtual void getExtraInvalidatedRegions(RegionList &Regions) const;
+
+public:
   virtual const CXXConstructExpr *getOriginExpr() const {
     return cast<CXXConstructExpr>(AnyFunctionCall::getOriginExpr());
   }
@@ -564,13 +586,9 @@
 /// This can occur at the end of a scope (for automatic objects), at the end
 /// of a full-expression (for temporaries), or as part of a delete.
 class CXXDestructorCall : public AnyFunctionCall {
-protected:
-  CXXDestructorCall(const CXXDestructorCall &Other) : AnyFunctionCall(Other) {}
-  virtual void cloneTo(void *Dest) const { new (Dest) CXXDestructorCall(*this); }
-
-  virtual void getExtraInvalidatedRegions(RegionList &Regions) const;
+  friend class CallEventManager;
 
-public:
+protected:
   /// Creates an implicit destructor.
   ///
   /// \param DD The destructor that will be called.
@@ -586,6 +604,12 @@
     Location = Trigger->getLocEnd();
   }
 
+  CXXDestructorCall(const CXXDestructorCall &Other) : AnyFunctionCall(Other) {}
+  virtual void cloneTo(void *Dest) const { new (Dest) CXXDestructorCall(*this); }
+
+  virtual void getExtraInvalidatedRegions(RegionList &Regions) const;
+
+public:
   virtual SourceRange getSourceRange() const { return Location; }
   virtual unsigned getNumArgs() const { return 0; }
 
@@ -603,15 +627,17 @@
 ///
 /// This is a call to "operator new".
 class CXXAllocatorCall : public AnyFunctionCall {
-protected:
-  CXXAllocatorCall(const CXXAllocatorCall &Other) : AnyFunctionCall(Other) {}
-  virtual void cloneTo(void *Dest) const { new (Dest) CXXAllocatorCall(*this); }
+  friend class CallEventManager;
 
-public:
+protected:
   CXXAllocatorCall(const CXXNewExpr *E, ProgramStateRef St,
                    const LocationContext *LCtx)
     : AnyFunctionCall(E, St, LCtx) {}
 
+  CXXAllocatorCall(const CXXAllocatorCall &Other) : AnyFunctionCall(Other) {}
+  virtual void cloneTo(void *Dest) const { new (Dest) CXXAllocatorCall(*this); }
+
+public:
   virtual const CXXNewExpr *getOriginExpr() const {
     return cast<CXXNewExpr>(AnyFunctionCall::getOriginExpr());
   }
@@ -652,9 +678,17 @@
 ///
 /// This includes all of the kinds listed in ObjCMessageKind.
 class ObjCMethodCall : public CallEvent {
+  friend class CallEventManager;
+
   const PseudoObjectExpr *getContainingPseudoObjectExpr() const;
 
 protected:
+  ObjCMethodCall(const ObjCMessageExpr *Msg, ProgramStateRef St,
+                 const LocationContext *LCtx)
+    : CallEvent(Msg, St, LCtx) {
+    Data = 0;
+  }
+
   ObjCMethodCall(const ObjCMethodCall &Other) : CallEvent(Other) {}
   virtual void cloneTo(void *Dest) const { new (Dest) ObjCMethodCall(*this); }
 
@@ -665,12 +699,6 @@
                                            ObjCInterfaceDecl *ClassDecl) const;
 
 public:
-  ObjCMethodCall(const ObjCMessageExpr *Msg, ProgramStateRef St,
-                 const LocationContext *LCtx)
-    : CallEvent(Msg, St, LCtx) {
-    Data = 0;
-  }
-
   virtual const ObjCMessageExpr *getOriginExpr() const {
     return cast<ObjCMessageExpr>(CallEvent::getOriginExpr());
   }
@@ -763,7 +791,7 @@
   friend class CallEvent;
 
   llvm::BumpPtrAllocator &Alloc;
-  SmallVector<void *, 4> Cache;
+  SmallVector<void *, 8> Cache;
 
   void reclaim(const void *Memory) {
     Cache.push_back(const_cast<void *>(Memory));
@@ -777,16 +805,64 @@
       return Cache.pop_back_val();
   }
 
+  template <typename T, typename Arg>
+  T *create(Arg A, ProgramStateRef St, const LocationContext *LCtx) {
+    return new (allocate()) T(A, St, LCtx);
+  }
+
+  template <typename T, typename Arg1, typename Arg2>
+  T *create(Arg1 A1, Arg2 A2, ProgramStateRef St, const LocationContext *LCtx) {
+    return new (allocate()) T(A1, A2, St, LCtx);
+  }
+
+  template <typename T, typename Arg1, typename Arg2, typename Arg3>
+  T *create(Arg1 A1, Arg2 A2, Arg3 A3, ProgramStateRef St,
+            const LocationContext *LCtx) {
+    return new (allocate()) T(A1, A2, A3, St, LCtx);
+  }
+
 public:
   CallEventManager(llvm::BumpPtrAllocator &alloc) : Alloc(alloc) {}
+
+  CallEventRef<SimpleCall>
+  getSimpleCall(const CallExpr *E, ProgramStateRef State,
+                const LocationContext *LCtx);
+
+  CallEventRef<ObjCMethodCall>
+  getObjCMethodCall(const ObjCMessageExpr *E, ProgramStateRef State,
+                    const LocationContext *LCtx) {
+    return create<ObjCMethodCall>(E, State, LCtx);
+  }
+
+  CallEventRef<CXXConstructorCall>
+  getCXXConstructorCall(const CXXConstructExpr *E, const MemRegion *Target,
+                        ProgramStateRef State, const LocationContext *LCtx) {
+    return create<CXXConstructorCall>(E, Target, State, LCtx);
+  }
+
+  CallEventRef<CXXDestructorCall>
+  getCXXDestructorCall(const CXXDestructorDecl *DD, const Stmt *Trigger,
+                       const MemRegion *Target, ProgramStateRef State,
+                       const LocationContext *LCtx) {
+    return create<CXXDestructorCall>(DD, Trigger, Target, State, LCtx);
+  }
+
+  CallEventRef<CXXAllocatorCall>
+  getCXXAllocatorCall(const CXXNewExpr *E, ProgramStateRef State,
+                      const LocationContext *LCtx) {
+    return create<CXXAllocatorCall>(E, State, LCtx);
+  }
 };
 
 
 template <typename T>
-IntrusiveRefCntPtr<T> CallEvent::cloneWithState(ProgramStateRef NewState) const{
+CallEventRef<T> CallEvent::cloneWithState(ProgramStateRef NewState) const {
   assert(isa<T>(*this) && "Cloning to unrelated type");
   assert(sizeof(T) == sizeof(CallEvent) && "Subclasses may not add fields");
 
+  if (NewState == State)
+    return cast<T>(this);
+
   CallEventManager &Mgr = State->getStateManager().getCallEventManager();
   T *Copy = static_cast<T *>(Mgr.allocate());
   cloneTo(Copy);

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h?rev=160986&r1=160985&r2=160986&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h Mon Jul 30 15:22:09 2012
@@ -43,7 +43,6 @@
 class AnalysisManager;
 class CallEvent;
 class SimpleCall;
-class ObjCMethodCall;
 
 class ExprEngine : public SubEngine {
   AnalysisManager &AMgr;
@@ -348,7 +347,7 @@
   void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S, 
                                   ExplodedNode *Pred, ExplodedNodeSet &Dst);
 
-  void VisitObjCMessage(const ObjCMethodCall &Msg, ExplodedNode *Pred,
+  void VisitObjCMessage(const ObjCMessageExpr *ME, ExplodedNode *Pred,
                         ExplodedNodeSet &Dst);
 
   /// VisitReturnStmt - Transfer function logic for return statements.

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp?rev=160986&r1=160985&r2=160986&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp Mon Jul 30 15:22:09 2012
@@ -1975,8 +1975,11 @@
       }
       else {
         assert(isa<ObjCMessageExpr>(S));
-        ObjCMethodCall Call(cast<ObjCMessageExpr>(S), CurrSt, LCtx);
-        switch (Call.getMessageKind()) {
+        CallEventManager &Mgr = CurrSt->getStateManager().getCallEventManager();
+        CallEventRef<ObjCMethodCall> Call
+          = Mgr.getObjCMethodCall(cast<ObjCMessageExpr>(S), CurrSt, LCtx);
+
+        switch (Call->getMessageKind()) {
         case OCM_Message:
           os << "Method";
           break;

Modified: cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp?rev=160986&r1=160985&r2=160986&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp Mon Jul 30 15:22:09 2012
@@ -620,3 +620,24 @@
   return Method;
 }
 
+
+CallEventRef<SimpleCall>
+CallEventManager::getSimpleCall(const CallExpr *CE, ProgramStateRef State,
+                                const LocationContext *LCtx) {
+  if (const CXXMemberCallExpr *MCE = dyn_cast<CXXMemberCallExpr>(CE))
+    return create<CXXMemberCall>(MCE, State, LCtx);
+
+  if (const CXXOperatorCallExpr *OpCE = dyn_cast<CXXOperatorCallExpr>(CE)) {
+    const FunctionDecl *DirectCallee = OpCE->getDirectCallee();
+    if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DirectCallee))
+      if (MD->isInstance())
+        return create<CXXMemberOperatorCall>(OpCE, State, LCtx);
+
+  } else if (CE->getCallee()->getType()->isBlockPointerType()) {
+    return create<BlockCall>(CE, State, LCtx);
+  }
+
+  // Otherwise, it's a normal function call, static member function call, or
+  // something we can't reason about.
+  return create<FunctionCall>(CE, State, LCtx);
+}

Modified: cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp?rev=160986&r1=160985&r2=160986&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp Mon Jul 30 15:22:09 2012
@@ -192,15 +192,10 @@
 
     void runChecker(CheckerManager::CheckObjCMessageFunc checkFn,
                     NodeBuilder &Bldr, ExplodedNode *Pred) {
-      ProgramPoint::Kind K =  IsPreVisit ? ProgramPoint::PreStmtKind :
-                                           ProgramPoint::PostStmtKind;
-      const ProgramPoint &L =
-        ProgramPoint::getProgramPoint(Msg.getOriginExpr(),
-                                      K, Pred->getLocationContext(),
-                                      checkFn.Checker);
+      const ProgramPoint &L = Msg.getProgramPoint(IsPreVisit,checkFn.Checker);
       CheckerContext C(Bldr, Eng, Pred, L);
 
-      checkFn(Msg, C);
+      checkFn(*Msg.cloneWithState<ObjCMethodCall>(Pred->getState()), C);
     }
   };
 }
@@ -237,10 +232,10 @@
 
     void runChecker(CheckerManager::CheckCallFunc checkFn,
                     NodeBuilder &Bldr, ExplodedNode *Pred) {
-      const ProgramPoint &L = Call.getProgramPoint(IsPreVisit, checkFn.Checker);
+      const ProgramPoint &L = Call.getProgramPoint(IsPreVisit,checkFn.Checker);
       CheckerContext C(Bldr, Eng, Pred, L);
 
-      checkFn(Call, C);
+      checkFn(*Call.cloneWithState(Pred->getState()), C);
     }
   };
 }

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=160986&r1=160985&r2=160986&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Mon Jul 30 15:22:09 2012
@@ -875,15 +875,11 @@
       Bldr.addNodes(Dst);
       break;
 
-    case Stmt::ObjCMessageExprClass: {
+    case Stmt::ObjCMessageExprClass:
       Bldr.takeNodes(Pred);
-      ObjCMethodCall Call(cast<ObjCMessageExpr>(S),
-                          Pred->getState(),
-                          Pred->getLocationContext());
-      VisitObjCMessage(Call, Pred, Dst);
+      VisitObjCMessage(cast<ObjCMessageExpr>(S), Pred, Dst);
       Bldr.addNodes(Dst);
       break;
-    }
 
     case Stmt::ObjCAtThrowStmtClass: {
       // FIXME: This is not complete.  We basically treat @throw as

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp?rev=160986&r1=160985&r2=160986&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Mon Jul 30 15:22:09 2012
@@ -125,23 +125,25 @@
   }
   }
 
-  CXXConstructorCall Call(CE, Target, State, LCtx);
+  CallEventManager &CEMgr = getStateManager().getCallEventManager();
+  CallEventRef<CXXConstructorCall> Call =
+    CEMgr.getCXXConstructorCall(CE, Target, State, LCtx);
 
   ExplodedNodeSet DstPreVisit;
   getCheckerManager().runCheckersForPreStmt(DstPreVisit, Pred, CE, *this);
   ExplodedNodeSet DstPreCall;
   getCheckerManager().runCheckersForPreCall(DstPreCall, DstPreVisit,
-                                            Call, *this);
+                                            *Call, *this);
 
   ExplodedNodeSet DstInvalidated;
   StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currentBuilderContext);
   for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
        I != E; ++I)
-    defaultEvalCall(Bldr, *I, Call);
+    defaultEvalCall(Bldr, *I, *Call);
 
   ExplodedNodeSet DstPostCall;
   getCheckerManager().runCheckersForPostCall(DstPostCall, DstInvalidated,
-                                             Call, *this);
+                                             *Call, *this);
   getCheckerManager().runCheckersForPostStmt(destNodes, DstPostCall, CE, *this);
 }
 
@@ -150,36 +152,39 @@
                                     const Stmt *S,
                                     ExplodedNode *Pred, 
                                     ExplodedNodeSet &Dst) {
+  const LocationContext *LCtx = Pred->getLocationContext();
+  ProgramStateRef State = Pred->getState();
+
   // FIXME: We need to run the same destructor on every element of the array.
   // This workaround will just run the first destructor (which will still
   // invalidate the entire array).
   if (const ArrayType *AT = getContext().getAsArrayType(ObjectType)) {
     ObjectType = AT->getElementType();
-    Dest = Pred->getState()->getLValue(ObjectType,
-                                       getSValBuilder().makeZeroArrayIndex(),
-                                       loc::MemRegionVal(Dest)).getAsRegion();
+    Dest = State->getLValue(ObjectType, getSValBuilder().makeZeroArrayIndex(),
+                            loc::MemRegionVal(Dest)).getAsRegion();
   }
 
   const CXXRecordDecl *RecordDecl = ObjectType->getAsCXXRecordDecl();
   assert(RecordDecl && "Only CXXRecordDecls should have destructors");
   const CXXDestructorDecl *DtorDecl = RecordDecl->getDestructor();
 
-  CXXDestructorCall Call(DtorDecl, S, Dest, Pred->getState(),
-                         Pred->getLocationContext());
+  CallEventManager &CEMgr = getStateManager().getCallEventManager();
+  CallEventRef<CXXDestructorCall> Call =
+    CEMgr.getCXXDestructorCall(DtorDecl, S, Dest, State, LCtx);
 
   ExplodedNodeSet DstPreCall;
   getCheckerManager().runCheckersForPreCall(DstPreCall, Pred,
-                                            Call, *this);
+                                            *Call, *this);
 
   ExplodedNodeSet DstInvalidated;
   StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currentBuilderContext);
   for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
        I != E; ++I)
-    defaultEvalCall(Bldr, *I, Call);
+    defaultEvalCall(Bldr, *I, *Call);
 
   ExplodedNodeSet DstPostCall;
   getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated,
-                                             Call, *this);
+                                             *Call, *this);
 }
 
 void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
@@ -196,9 +201,14 @@
     svalBuilder.getConjuredSymbolVal(0, CNE, LCtx, CNE->getType(), blockCount);
   ProgramStateRef State = Pred->getState();
 
+  CallEventManager &CEMgr = getStateManager().getCallEventManager();
+  CallEventRef<CXXAllocatorCall> Call =
+    CEMgr.getCXXAllocatorCall(CNE, State, LCtx);
+
   // Invalidate placement args.
-  CXXAllocatorCall Call(CNE, State, LCtx);
-  State = Call.invalidateRegions(blockCount);
+  // FIXME: Once we figure out how we want allocators to work,
+  // we should be using the usual pre-/(default-)eval-/post-call checks here.
+  State = Call->invalidateRegions(blockCount);
 
   if (CNE->isArray()) {
     // FIXME: allocating an array requires simulating the constructors.

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp?rev=160986&r1=160985&r2=160986&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp Mon Jul 30 15:22:09 2012
@@ -22,23 +22,6 @@
 using namespace clang;
 using namespace ento;
 
-static CallEventKind classifyCallExpr(const CallExpr *CE) {
-  if (isa<CXXMemberCallExpr>(CE))
-    return CE_CXXMember;
-
-  const CXXOperatorCallExpr *OpCE = dyn_cast<CXXOperatorCallExpr>(CE);
-  if (OpCE) {
-    const FunctionDecl *DirectCallee = CE->getDirectCallee();
-    if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DirectCallee))
-      if (MD->isInstance())
-        return CE_CXXMemberOperator;
-  } else if (CE->getCallee()->getType()->isBlockPointerType()) {
-    return CE_Block;
-  }
-
-  return CE_Function;
-}
-
 void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) {
   // Get the entry block in the CFG of the callee.
   const StackFrameContext *calleeCtx = CE.getCalleeContext();
@@ -387,42 +370,18 @@
   ExplodedNodeSet dstPreVisit;
   getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, CE, *this);
 
-  // Get the callee kind.
-  CallEventKind K = classifyCallExpr(CE);
+  // Get the call in its initial state. We use this as a template to perform
+  // all the checks.
+  CallEventManager &CEMgr = getStateManager().getCallEventManager();
+  CallEventRef<SimpleCall> CallTemplate
+    = CEMgr.getSimpleCall(CE, Pred->getState(), Pred->getLocationContext());
 
   // Evaluate the function call.  We try each of the checkers
   // to see if the can evaluate the function call.
   ExplodedNodeSet dstCallEvaluated;
   for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end();
        I != E; ++I) {
-    ProgramStateRef State = (*I)->getState();
-    const LocationContext *LCtx = (*I)->getLocationContext();
-
-    // Evaluate the call.
-    switch (K) {
-    case CE_Function: {
-      FunctionCall Call(CE, State, LCtx);
-      evalCall(dstCallEvaluated, *I, Call);
-      break;
-    }
-    case CE_CXXMember: {
-      CXXMemberCall Call(cast<CXXMemberCallExpr>(CE), State, LCtx);
-      evalCall(dstCallEvaluated, *I, Call);
-      break;
-    }
-    case CE_CXXMemberOperator: {
-      CXXMemberOperatorCall Call(cast<CXXOperatorCallExpr>(CE), State, LCtx);
-      evalCall(dstCallEvaluated, *I, Call);
-      break;
-    }
-    case CE_Block: {
-      BlockCall Call(CE, State, LCtx);
-      evalCall(dstCallEvaluated, *I, Call);
-      break;
-    }
-    default:
-      llvm_unreachable("Non-CallExpr CallEventKind");
-    }
+    evalCall(dstCallEvaluated, *I, *CallTemplate);
   }
 
   // Finally, perform the post-condition check of the CallExpr and store
@@ -435,6 +394,13 @@
 
 void ExprEngine::evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
                           const SimpleCall &Call) {
+  // WARNING: At this time, the state attached to 'Call' may be older than the
+  // state in 'Pred'. This is a minor optimization since CheckerManager will
+  // use an updated CallEvent instance when calling checkers, but if 'Call' is
+  // ever used directly in this function all callers should be updated to pass
+  // the most recent state. (It is probably not worth doing the work here since
+  // for some callers this will not be necessary.)
+
   // Run any pre-call checks using the generic call interface.
   ExplodedNodeSet dstPreVisit;
   getCheckerManager().runCheckersForPreCall(dstPreVisit, Pred, Call, *this);
@@ -483,36 +449,35 @@
 }
 
 void ExprEngine::defaultEvalCall(NodeBuilder &Bldr, ExplodedNode *Pred,
-                                 const CallEvent &Call) {
-  ProgramStateRef State = 0;
-  const Expr *E = Call.getOriginExpr();
+                                 const CallEvent &CallTemplate) {
+  // Make sure we have the most recent state attached to the call.
+  ProgramStateRef State = Pred->getState();
+  CallEventRef<> Call = CallTemplate.cloneWithState(State);
 
   // Try to inline the call.
   // The origin expression here is just used as a kind of checksum;
-  // for CallEvents that do not have origin expressions, this should still be
-  // safe.
-  State = getInlineFailedState(Pred->getState(), E);
-  if (State == 0 && inlineCall(Call, Pred)) {
-    // If we inlined the call, the successor has been manually added onto
-    // the work list and we should not consider it for subsequent call
-    // handling steps.
+  // this should still be safe even for CallEvents that don't come from exprs.
+  const Expr *E = Call->getOriginExpr();
+  ProgramStateRef InlinedFailedState = getInlineFailedState(State, E);
+
+  if (InlinedFailedState) {
+    // If we already tried once and failed, make sure we don't retry later.
+    State = InlinedFailedState;
+  } else if (inlineCall(*Call, Pred)) {
+    // If we decided to inline the call, the successor has been manually
+    // added onto the work list and we should not perform our generic
+    // call-handling steps.
     Bldr.takeNodes(Pred);
     return;
   }
 
   // If we can't inline it, handle the return value and invalidate the regions.
-  if (State == 0)
-    State = Pred->getState();
-
-  // Invalidate any regions touched by the call.
   unsigned Count = currentBuilderContext->getCurrentBlockCount();
-  State = Call.invalidateRegions(Count, State);
-
-  // Construct and bind the return value.
-  State = bindReturnValue(Call, Pred->getLocationContext(), State);
+  State = Call->invalidateRegions(Count, State);
+  State = bindReturnValue(*Call, Pred->getLocationContext(), State);
 
   // And make the result node.
-  Bldr.generateNode(Call.getProgramPoint(), State, Pred);
+  Bldr.generateNode(Call->getProgramPoint(), State, Pred);
 }
 
 void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, 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=160986&r1=160985&r2=160986&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp Mon Jul 30 15:22:09 2012
@@ -140,17 +140,20 @@
   return isSubclass(Class->getSuperClass(), II);
 }
 
-void ExprEngine::VisitObjCMessage(const ObjCMethodCall &msg,
+void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
                                   ExplodedNode *Pred,
                                   ExplodedNodeSet &Dst) {
-  
+  CallEventManager &CEMgr = getStateManager().getCallEventManager();
+  CallEventRef<ObjCMethodCall> Msg =
+    CEMgr.getObjCMethodCall(ME, Pred->getState(), Pred->getLocationContext());
+
   // Handle the previsits checks.
   ExplodedNodeSet dstPrevisit;
   getCheckerManager().runCheckersForPreObjCMessage(dstPrevisit, Pred,
-                                                   msg, *this);
+                                                   *Msg, *this);
   ExplodedNodeSet dstGenericPrevisit;
   getCheckerManager().runCheckersForPreCall(dstGenericPrevisit, dstPrevisit,
-                                            msg, *this);
+                                            *Msg, *this);
 
   // Proceed with evaluate the message expression.
   ExplodedNodeSet dstEval;
@@ -159,16 +162,17 @@
   for (ExplodedNodeSet::iterator DI = dstGenericPrevisit.begin(),
        DE = dstGenericPrevisit.end(); DI != DE; ++DI) {
     ExplodedNode *Pred = *DI;
+    ProgramStateRef State = Pred->getState();
+    CallEventRef<ObjCMethodCall> UpdatedMsg = Msg.cloneWithState(State);
     
-    if (msg.isInstanceMessage()) {
-      SVal recVal = msg.getReceiverSVal();
+    if (UpdatedMsg->isInstanceMessage()) {
+      SVal recVal = UpdatedMsg->getReceiverSVal();
       if (!recVal.isUndef()) {
         // Bifurcate the state into nil and non-nil ones.
         DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
         
-        ProgramStateRef state = Pred->getState();
         ProgramStateRef notNilState, nilState;
-        llvm::tie(notNilState, nilState) = state->assume(receiverVal);
+        llvm::tie(notNilState, nilState) = State->assume(receiverVal);
         
         // There are three cases: can be nil or non-nil, must be nil, must be
         // non-nil. We ignore must be nil, and merge the rest two into non-nil.
@@ -180,20 +184,20 @@
         
         // Check if the "raise" message was sent.
         assert(notNilState);
-        if (msg.getSelector() == RaiseSel) {
+        if (Msg->getSelector() == RaiseSel) {
           // If we raise an exception, for now treat it as a sink.
           // Eventually we will want to handle exceptions properly.
-          Bldr.generateNode(currentStmt, Pred, Pred->getState(), true);
+          Bldr.generateNode(currentStmt, Pred, State, true);
           continue;
         }
         
         // Generate a transition to non-Nil state.
-        if (notNilState != state)
+        if (notNilState != State)
           Pred = Bldr.generateNode(currentStmt, Pred, notNilState);
       }
     } else {
       // Check for special class methods.
-      if (const ObjCInterfaceDecl *Iface = msg.getReceiverInterface()) {
+      if (const ObjCInterfaceDecl *Iface = Msg->getReceiverInterface()) {
         if (!NSExceptionII) {
           ASTContext &Ctx = getContext();
           NSExceptionII = &Ctx.Idents.get("NSException");
@@ -222,7 +226,7 @@
               Ctx.Selectors.getSelector(II.size(), &II[0]);
           }
           
-          Selector S = msg.getSelector();
+          Selector S = Msg->getSelector();
           bool RaisesException = false;
           for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) {
             if (S == NSExceptionInstanceRaiseSelectors[i]) {
@@ -240,16 +244,17 @@
         }
       }
     }
-    // Evaluate the call.
-    defaultEvalCall(Bldr, Pred, msg);
 
+    // Evaluate the call.
+    defaultEvalCall(Bldr, Pred, *UpdatedMsg);
   }
   
   ExplodedNodeSet dstPostvisit;
-  getCheckerManager().runCheckersForPostCall(dstPostvisit, dstEval, msg, *this);
+  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, dstPostvisit,
-                                                    msg, *this);
+                                                    *Msg, *this);
 }





More information about the cfe-commits mailing list