[cfe-commits] r138718 - in /cfe/trunk: include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h lib/StaticAnalyzer/Core/CFRefCount.cpp lib/StaticAnalyzer/Core/ExprEngineCXX.cpp lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp lib/StaticAnalyzer/Core/ExprEngineObjC.cpp lib/StaticAnalyzer/Core/ObjCMessage.cpp

Jordy Rose jediknil at belkadan.com
Sat Aug 27 22:16:28 PDT 2011


Author: jrose
Date: Sun Aug 28 00:16:28 2011
New Revision: 138718

URL: http://llvm.org/viewvc/llvm-project?rev=138718&view=rev
Log:
[analyzer] Migrate argument invalidation from CFRefCount to ExprEngine.

This is a common path for function and C++ method calls, Objective-C messages and property accesses, and C++ construct-exprs.

As support, add message receiver accessors to ObjCMessage and CallOrObjCMessage.

Modified:
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
    cfe/trunk/lib/StaticAnalyzer/Core/CFRefCount.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ObjCMessage.cpp

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=138718&r1=138717&r2=138718&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h Sun Aug 28 00:16:28 2011
@@ -410,6 +410,10 @@
   void evalObjCMessage(ExplodedNodeSet &Dst, const ObjCMessage &msg, 
                        ExplodedNode *Pred, const ProgramState *state);
 
+  const ProgramState *invalidateArguments(const ProgramState *State,
+                                          const CallOrObjCMessage &Call,
+                                          const LocationContext *LC);
+
   const ProgramState *MarkBranch(const ProgramState *St, const Stmt *Terminator,
                             bool branchTaken);
 

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h?rev=138718&r1=138717&r2=138718&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h Sun Aug 28 00:16:28 2011
@@ -88,6 +88,21 @@
     return 0;
   }
 
+  SVal getInstanceReceiverSVal(const ProgramState *State,
+                               const LocationContext *LC) const {
+    assert(isValid() && "This ObjCMessage is uninitialized!");
+    if (!isInstanceMessage())
+      return UndefinedVal();
+    if (const Expr *Ex = getInstanceReceiver())
+      return State->getSValAsScalarOrLoc(Ex);
+
+    // An instance message with no expression means we are sending to super.
+    // In this case the object reference is the same as 'self'.
+    const ImplicitParamDecl *SelfDecl = LC->getSelfDecl();
+    assert(SelfDecl && "No message receiver Expr, but not in an ObjC method");
+    return State->getSVal(State->getRegion(SelfDecl, LC));
+  }
+
   bool isInstanceMessage() const {
     assert(isValid() && "This ObjCMessage is uninitialized!");
     if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
@@ -98,7 +113,7 @@
   }
 
   const ObjCMethodDecl *getMethodDecl() const;
-  
+
   const ObjCInterfaceDecl *getReceiverInterface() const;
 
   SourceLocation getSuperLoc() const {
@@ -108,45 +123,58 @@
     return cast<ObjCPropertyRefExpr>(MsgOrPropE)->getReceiverLocation();
   }
 
-   SourceRange getSourceRange() const {
-     assert(isValid() && "This ObjCMessage is uninitialized!");
+  SourceRange getSourceRange() const {
+    assert(isValid() && "This ObjCMessage is uninitialized!");
     return MsgOrPropE->getSourceRange();
   }
 
-   unsigned getNumArgs() const {
-     assert(isValid() && "This ObjCMessage is uninitialized!");
-     if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
-       return msgE->getNumArgs();
-     return isPropertySetter() ? 1 : 0;
-   }
-
-   SVal getArgSVal(unsigned i, const ProgramState *state) const {
-     assert(isValid() && "This ObjCMessage is uninitialized!");
-     assert(i < getNumArgs() && "Invalid index for argument");
-     if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
-       return state->getSVal(msgE->getArg(i));
-     assert(isPropertySetter());
-     return SetterArgV;
-   }
-
-   QualType getArgType(unsigned i) const {
-     assert(isValid() && "This ObjCMessage is uninitialized!");
-     assert(i < getNumArgs() && "Invalid index for argument");
-     if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
-       return msgE->getArg(i)->getType();
-     assert(isPropertySetter());
-     return cast<ObjCPropertyRefExpr>(MsgOrPropE)->getType();
-   }
-   
-   const Expr *getArgExpr(unsigned i) const;
-
-   SourceRange getArgSourceRange(unsigned i) const {
-     assert(isValid() && "This ObjCMessage is uninitialized!");
-     assert(i < getNumArgs() && "Invalid index for argument");
-     if (const Expr *argE = getArgExpr(i))
-       return argE->getSourceRange();
-     return OriginE->getSourceRange();
-   }
+  unsigned getNumArgs() const {
+    assert(isValid() && "This ObjCMessage is uninitialized!");
+    if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+      return msgE->getNumArgs();
+    return isPropertySetter() ? 1 : 0;
+  }
+
+  SVal getArgSVal(unsigned i, const ProgramState *state) const {
+    assert(isValid() && "This ObjCMessage is uninitialized!");
+    assert(i < getNumArgs() && "Invalid index for argument");
+    if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+      return state->getSVal(msgE->getArg(i));
+    assert(isPropertySetter());
+    return SetterArgV;
+  }
+
+  QualType getArgType(unsigned i) const {
+    assert(isValid() && "This ObjCMessage is uninitialized!");
+    assert(i < getNumArgs() && "Invalid index for argument");
+    if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+      return msgE->getArg(i)->getType();
+    assert(isPropertySetter());
+    return cast<ObjCPropertyRefExpr>(MsgOrPropE)->getType();
+  }
+
+  const Expr *getArgExpr(unsigned i) const;
+
+  SourceRange getArgSourceRange(unsigned i) const {
+    assert(isValid() && "This ObjCMessage is uninitialized!");
+    assert(i < getNumArgs() && "Invalid index for argument");
+    if (const Expr *argE = getArgExpr(i))
+      return argE->getSourceRange();
+    return OriginE->getSourceRange();
+  }
+
+  SourceRange getReceiverSourceRange() const {
+    assert(isValid() && "This ObjCMessage is uninitialized!");
+    if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE))
+      return msgE->getReceiverRange();
+
+    const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE);
+    if (propE->isObjectReceiver())
+      return propE->getBase()->getSourceRange();
+
+    // FIXME: This isn't a range.
+    return propE->getReceiverLocation();
+  }
 };
 
 class ObjCPropertyGetter : public ObjCMessage {
@@ -211,6 +239,7 @@
   
   SVal getFunctionCallee() const;
   SVal getCXXCallee() const;
+  SVal getInstanceMessageReceiver(const LocationContext *LC) const;
 
   unsigned getNumArgs() const {
     if (!CallE)
@@ -244,6 +273,11 @@
       return getArg(i)->getSourceRange();
     return Msg.getArgSourceRange(i);
   }
+
+  SourceRange getReceiverSourceRange() const {
+    assert(isObjCMessage());
+    return Msg.getReceiverSourceRange();
+  }
 };
 
 }

Modified: cfe/trunk/lib/StaticAnalyzer/Core/CFRefCount.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CFRefCount.cpp?rev=138718&r1=138717&r2=138718&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CFRefCount.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CFRefCount.cpp Sun Aug 28 00:16:28 2011
@@ -41,50 +41,6 @@
 using llvm::StrInStrNoCase;
 
 namespace {
-class InstanceReceiver {
-  ObjCMessage Msg;
-  const LocationContext *LC;
-public:
-  InstanceReceiver() : LC(0) { }
-  InstanceReceiver(const ObjCMessage &msg,
-                   const LocationContext *lc = 0) : Msg(msg), LC(lc) {}
-
-  bool isValid() const {
-    return Msg.isValid() && Msg.isInstanceMessage();
-  }
-  operator bool() const {
-    return isValid();
-  }
-
-  SVal getSValAsScalarOrLoc(const ProgramState *state) {
-    assert(isValid());
-    // We have an expression for the receiver?  Fetch the value
-    // of that expression.
-    if (const Expr *Ex = Msg.getInstanceReceiver())
-      return state->getSValAsScalarOrLoc(Ex);
-
-    // Otherwise we are sending a message to super.  In this case the
-    // object reference is the same as 'self'.
-    if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl())
-      return state->getSVal(state->getRegion(SelfDecl, LC));
-
-    return UnknownVal();
-  }
-
-  SourceRange getSourceRange() const {
-    assert(isValid());
-    if (const Expr *Ex = Msg.getInstanceReceiver())
-      return Ex->getSourceRange();
-
-    // Otherwise we are sending a message to super.
-    SourceLocation L = Msg.getSuperLoc();
-    assert(L.isValid());
-    return SourceRange(L, L);
-  }
-};
-}
-
-namespace {
 class GenericNodeBuilderRefCount {
   StmtNodeBuilder *SNB;
   const Stmt *S;
@@ -1651,28 +1607,6 @@
   }
   
   const LangOptions& getLangOptions() const { return LOpts; }
-
-  // Calls.
-
-  void evalCallOrMessage(ExplodedNodeSet &Dst, ExprEngine &Eng,
-                         StmtNodeBuilder &Builder,
-                         const CallOrObjCMessage &callOrMsg,
-                         InstanceReceiver Receiver, const MemRegion *Callee,
-                         ExplodedNode *Pred, const ProgramState *state);
-
-  virtual void evalCall(ExplodedNodeSet &Dst,
-                        ExprEngine& Eng,
-                        StmtNodeBuilder& Builder,
-                        const CallExpr *CE, SVal L,
-                        ExplodedNode *Pred);
-
-
-  virtual void evalObjCMessage(ExplodedNodeSet &Dst,
-                               ExprEngine& Engine,
-                               StmtNodeBuilder& Builder,
-                               ObjCMessage msg,
-                               ExplodedNode *Pred,
-                               const ProgramState *state);
 };
 
 } // end anonymous namespace
@@ -2439,133 +2373,6 @@
   return RetTy;
 }
 
-void CFRefCount::evalCallOrMessage(ExplodedNodeSet &Dst, ExprEngine &Eng,
-                                   StmtNodeBuilder &Builder,
-                                   const CallOrObjCMessage &callOrMsg,
-                                   InstanceReceiver Receiver,
-                                   const MemRegion *Callee,
-                                   ExplodedNode *Pred,
-                                   const ProgramState *state) {
-
-  SmallVector<const MemRegion*, 10> RegionsToInvalidate;
-
-  // Invalidate all instance variables of the receiver of a message.
-  // FIXME: We should be able to do better with inter-procedural analysis.
-  if (Receiver) {
-    SVal V = Receiver.getSValAsScalarOrLoc(state);
-    if (const MemRegion *region = V.getAsRegion())
-      RegionsToInvalidate.push_back(region);
-  }
-  
-  // Invalidate all instance variables for the callee of a C++ method call.
-  // FIXME: We should be able to do better with inter-procedural analysis.
-  // FIXME: we can probably do better for const versus non-const methods.
-  if (callOrMsg.isCXXCall()) {
-    if (const MemRegion *callee = callOrMsg.getCXXCallee().getAsRegion())
-      RegionsToInvalidate.push_back(callee);
-  }
-  
-  for (unsigned idx = 0, e = callOrMsg.getNumArgs(); idx != e; ++idx) {
-    SVal V = callOrMsg.getArgSVal(idx);
-
-    // If we are passing a location wrapped as an integer, unwrap it and
-    // invalidate the values referred by the location.
-    if (nonloc::LocAsInteger *Wrapped = dyn_cast<nonloc::LocAsInteger>(&V))
-      V = Wrapped->getLoc();
-    else if (!isa<Loc>(V))
-      continue;
-
-    if (const MemRegion *R = V.getAsRegion()) {
-      // Invalidate the value of the variable passed by reference.
-
-      // Are we dealing with an ElementRegion?  If the element type is
-      // a basic integer type (e.g., char, int) and the underying region
-      // is a variable region then strip off the ElementRegion.
-      // FIXME: We really need to think about this for the general case
-      //   as sometimes we are reasoning about arrays and other times
-      //   about (char*), etc., is just a form of passing raw bytes.
-      //   e.g., void *p = alloca(); foo((char*)p);
-      if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
-        // Checking for 'integral type' is probably too promiscuous, but
-        // we'll leave it in for now until we have a systematic way of
-        // handling all of these cases.  Eventually we need to come up
-        // with an interface to StoreManager so that this logic can be
-        // approriately delegated to the respective StoreManagers while
-        // still allowing us to do checker-specific logic (e.g.,
-        // invalidating reference counts), probably via callbacks.
-        if (ER->getElementType()->isIntegralOrEnumerationType()) {
-          const MemRegion *superReg = ER->getSuperRegion();
-          if (isa<VarRegion>(superReg) || isa<FieldRegion>(superReg) ||
-              isa<ObjCIvarRegion>(superReg))
-            R = cast<TypedRegion>(superReg);
-        }
-        // FIXME: What about layers of ElementRegions?
-      }
-
-      // Mark this region for invalidation.  We batch invalidate regions
-      // below for efficiency.
-      RegionsToInvalidate.push_back(R);
-    } else {
-      // Nuke all other arguments passed by reference.
-      // FIXME: is this necessary or correct? This handles the non-Region
-      //  cases.  Is it ever valid to store to these?
-      state = state->unbindLoc(cast<Loc>(V));
-    }
-  }
-
-  // Block calls result in all captured values passed-via-reference to be
-  // invalidated.
-  if (const BlockDataRegion *BR = dyn_cast_or_null<BlockDataRegion>(Callee))
-    RegionsToInvalidate.push_back(BR);
-
-  // Invalidate designated regions using the batch invalidation API.
-
-  // FIXME: We can have collisions on the conjured symbol if the
-  //  expression *I also creates conjured symbols.  We probably want
-  //  to identify conjured symbols by an expression pair: the enclosing
-  //  expression (the context) and the expression itself.  This should
-  //  disambiguate conjured symbols.
-  unsigned Count = Builder.getCurrentBlockCount();
-  StoreManager::InvalidatedSymbols IS;
-
-  const Expr *Ex = callOrMsg.getOriginExpr();
-
-  // NOTE: Even if RegionsToInvalidate is empty, we must still invalidate
-  //  global variables.
-  // NOTE: RetainReleaseChecker handles the actual invalidation of symbols.
-  state =
-    state->invalidateRegions(RegionsToInvalidate,
-                             Ex, Count, &IS,
-                             /* invalidateGlobals = */
-                             Eng.doesInvalidateGlobals(callOrMsg));
-
-  Builder.MakeNode(Dst, Ex, Pred, state);
-}
-
-
-void CFRefCount::evalCall(ExplodedNodeSet &Dst,
-                          ExprEngine& Eng,
-                          StmtNodeBuilder& Builder,
-                          const CallExpr *CE, SVal L,
-                          ExplodedNode *Pred) {
-
-  evalCallOrMessage(Dst, Eng, Builder, CallOrObjCMessage(CE, Pred->getState()),
-                    InstanceReceiver(), L.getAsRegion(), Pred, 
-                    Pred->getState());
-}
-
-void CFRefCount::evalObjCMessage(ExplodedNodeSet &Dst,
-                                 ExprEngine& Eng,
-                                 StmtNodeBuilder& Builder,
-                                 ObjCMessage msg,
-                                 ExplodedNode *Pred,
-                                 const ProgramState *state) {
-
-  evalCallOrMessage(Dst, Eng, Builder, CallOrObjCMessage(msg, Pred->getState()),
-                    InstanceReceiver(msg, Pred->getLocationContext()),
-                    /* Callee = */ 0, Pred, state);
-}
-
 //===----------------------------------------------------------------------===//
 // Pieces of the retain/release checker implemented using a CheckerVisitor.
 // More pieces of the retain/release checker will be migrated to this interface
@@ -2744,7 +2551,7 @@
   void checkPostStmt(const CXXConstructExpr *CE, CheckerContext &C) const;
   void checkPostObjCMessage(const ObjCMessage &Msg, CheckerContext &C) const;
   void checkSummary(const RetainSummary &Summ, const CallOrObjCMessage &Call,
-                    InstanceReceiver Receiver, CheckerContext &C) const;
+                    CheckerContext &C) const;
 
   bool evalCall(const CallExpr *CE, CheckerContext &C) const;
 
@@ -3013,7 +2820,7 @@
   if (!Summ)
     return;
 
-  checkSummary(*Summ, CallOrObjCMessage(CE, state), InstanceReceiver(), C);
+  checkSummary(*Summ, CallOrObjCMessage(CE, state), C);
 }
 
 void RetainReleaseChecker::checkPostStmt(const CXXConstructExpr *CE,
@@ -3030,7 +2837,7 @@
     return;
 
   const ProgramState *state = C.getState();
-  checkSummary(*Summ, CallOrObjCMessage(CE, state), InstanceReceiver(), C);
+  checkSummary(*Summ, CallOrObjCMessage(CE, state), C);
 }
 
 void RetainReleaseChecker::checkPostObjCMessage(const ObjCMessage &Msg, 
@@ -3052,13 +2859,11 @@
   if (!Summ)
     return;
 
-  checkSummary(*Summ, CallOrObjCMessage(Msg, state),
-               InstanceReceiver(Msg, Pred->getLocationContext()), C);
+  checkSummary(*Summ, CallOrObjCMessage(Msg, state), C);
 }
 
 void RetainReleaseChecker::checkSummary(const RetainSummary &Summ,
                                         const CallOrObjCMessage &CallOrMsg,
-                                        InstanceReceiver Receiver,
                                         CheckerContext &C) const {
   const ProgramState *state = C.getState();
 
@@ -3084,13 +2889,15 @@
 
   // Evaluate the effect on the message receiver.
   bool ReceiverIsTracked = false;
-  if (!hasErr && Receiver) {
-    if (SymbolRef Sym = Receiver.getSValAsScalarOrLoc(state).getAsLocSymbol()) {
+  if (!hasErr && CallOrMsg.isObjCMessage()) {
+    const LocationContext *LC = C.getPredecessor()->getLocationContext();
+    SVal Receiver = CallOrMsg.getInstanceMessageReceiver(LC);
+    if (SymbolRef Sym = Receiver.getAsLocSymbol()) {
       if (const RefVal *T = state->get<RefBindings>(Sym)) {
         ReceiverIsTracked = true;
         state = updateSymbol(state, Sym, *T, Summ.getReceiverEffect(), hasErr);
         if (hasErr) {
-          ErrorRange = Receiver.getSourceRange();
+          ErrorRange = CallOrMsg.getReceiverSourceRange();
           ErrorSym = Sym;
         }
       }

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp?rev=138718&r1=138717&r2=138718&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Sun Aug 28 00:16:28 2011
@@ -198,17 +198,6 @@
 #endif
   
   // Default semantics: invalidate all regions passed as arguments.
-  SmallVector<const MemRegion*, 10> regionsToInvalidate;
-
-  // FIXME: We can have collisions on the conjured symbol if the
-  //  expression *I also creates conjured symbols.  We probably want
-  //  to identify conjured symbols by an expression pair: the enclosing
-  //  expression (the context) and the expression itself.  This should
-  //  disambiguate conjured symbols.
-  unsigned blockCount = Builder->getCurrentBlockCount();
-  
-  // NOTE: Even if RegionsToInvalidate is empty, we must still invalidate
-  //  global variables.
   ExplodedNodeSet destCall;
 
   for (ExplodedNodeSet::iterator
@@ -216,23 +205,10 @@
        i != e; ++i)
   {
     ExplodedNode *Pred = *i;
+    const LocationContext *LC = Pred->getLocationContext();
     const ProgramState *state = Pred->getState();
 
-    // Accumulate list of regions that are invalidated.
-    for (CXXConstructExpr::const_arg_iterator
-          ai = E->arg_begin(), ae = E->arg_end();
-          ai != ae; ++ai)
-    {
-      SVal val = state->getSVal(*ai);
-      if (const MemRegion *region = val.getAsRegion())
-        regionsToInvalidate.push_back(region);
-    }
-    
-    // Invalidate the regions.    
-    state = state->invalidateRegions(regionsToInvalidate,
-                                     E, blockCount, 0,
-                                     /* invalidateGlobals = */ true);
-    
+    state = invalidateArguments(state, CallOrObjCMessage(E, state), LC);
     Builder->MakeNode(destCall, E, Pred, state);
   }
   

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp?rev=138718&r1=138717&r2=138718&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp Sun Aug 28 00:16:28 2011
@@ -13,6 +13,7 @@
 
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/Analysis/Support/SaveAndRestore.h"
 
@@ -63,6 +64,100 @@
   B.generateNode(state);
 }
 
+const ProgramState *
+ExprEngine::invalidateArguments(const ProgramState *State,
+                                const CallOrObjCMessage &Call,
+                                const LocationContext *LC) {
+  SmallVector<const MemRegion *, 8> RegionsToInvalidate;
+
+  if (Call.isObjCMessage()) {
+    // Invalidate all instance variables of the receiver of an ObjC message.
+    // FIXME: We should be able to do better with inter-procedural analysis.
+    if (const MemRegion *MR = Call.getInstanceMessageReceiver(LC).getAsRegion())
+      RegionsToInvalidate.push_back(MR);
+
+  } else if (Call.isCXXCall()) {
+    // Invalidate all instance variables for the callee of a C++ method call.
+    // FIXME: We should be able to do better with inter-procedural analysis.
+    // FIXME: We can probably do better for const versus non-const methods.
+    if (const MemRegion *Callee = Call.getCXXCallee().getAsRegion())
+      RegionsToInvalidate.push_back(Callee);
+
+  } else if (Call.isFunctionCall()) {
+    // Block calls invalidate all captured-by-reference values.
+    if (const MemRegion *Callee = Call.getFunctionCallee().getAsRegion()) {
+      if (isa<BlockDataRegion>(Callee))
+        RegionsToInvalidate.push_back(Callee);
+    }
+  }
+
+  for (unsigned idx = 0, e = Call.getNumArgs(); idx != e; ++idx) {
+    SVal V = Call.getArgSVal(idx);
+
+    // If we are passing a location wrapped as an integer, unwrap it and
+    // invalidate the values referred by the location.
+    if (nonloc::LocAsInteger *Wrapped = dyn_cast<nonloc::LocAsInteger>(&V))
+      V = Wrapped->getLoc();
+    else if (!isa<Loc>(V))
+      continue;
+
+    if (const MemRegion *R = V.getAsRegion()) {
+      // Invalidate the value of the variable passed by reference.
+
+      // Are we dealing with an ElementRegion?  If the element type is
+      // a basic integer type (e.g., char, int) and the underying region
+      // is a variable region then strip off the ElementRegion.
+      // FIXME: We really need to think about this for the general case
+      //   as sometimes we are reasoning about arrays and other times
+      //   about (char*), etc., is just a form of passing raw bytes.
+      //   e.g., void *p = alloca(); foo((char*)p);
+      if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+        // Checking for 'integral type' is probably too promiscuous, but
+        // we'll leave it in for now until we have a systematic way of
+        // handling all of these cases.  Eventually we need to come up
+        // with an interface to StoreManager so that this logic can be
+        // approriately delegated to the respective StoreManagers while
+        // still allowing us to do checker-specific logic (e.g.,
+        // invalidating reference counts), probably via callbacks.
+        if (ER->getElementType()->isIntegralOrEnumerationType()) {
+          const MemRegion *superReg = ER->getSuperRegion();
+          if (isa<VarRegion>(superReg) || isa<FieldRegion>(superReg) ||
+              isa<ObjCIvarRegion>(superReg))
+            R = cast<TypedRegion>(superReg);
+        }
+        // FIXME: What about layers of ElementRegions?
+      }
+
+      // Mark this region for invalidation.  We batch invalidate regions
+      // below for efficiency.
+      RegionsToInvalidate.push_back(R);
+    } else {
+      // Nuke all other arguments passed by reference.
+      // FIXME: is this necessary or correct? This handles the non-Region
+      //  cases.  Is it ever valid to store to these?
+      State = State->unbindLoc(cast<Loc>(V));
+    }
+  }
+
+  // Invalidate designated regions using the batch invalidation API.
+
+  // FIXME: We can have collisions on the conjured symbol if the
+  //  expression *I also creates conjured symbols.  We probably want
+  //  to identify conjured symbols by an expression pair: the enclosing
+  //  expression (the context) and the expression itself.  This should
+  //  disambiguate conjured symbols.
+  assert(Builder && "Invalidating arguments outside of a statement context");
+  unsigned Count = Builder->getCurrentBlockCount();
+  StoreManager::InvalidatedSymbols IS;
+
+  // NOTE: Even if RegionsToInvalidate is empty, we may still invalidate
+  //  global variables.
+  return State->invalidateRegions(RegionsToInvalidate,
+                                  Call.getOriginExpr(), Count,
+                                  &IS, doesInvalidateGlobals(Call));
+
+}
+
 void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred,
                                ExplodedNodeSet &dst) {
   // Perform the previsit of the CallExpr.
@@ -108,16 +203,19 @@
       unsigned Count = Builder.getCurrentBlockCount();
       SVal RetVal = SVB.getConjuredSymbolVal(0, CE, ResultTy, Count);
 
-      // Generate a new ExplodedNode with the return value set.
+      // Generate a new state with the return value set.
       state = state->BindExpr(CE, RetVal);
-      Pred = Builder.generateNode(CE, state, Pred);
+
+      // Invalidate the arguments.
+      const LocationContext *LC = Pred->getLocationContext();
+      state = Eng.invalidateArguments(state, CallOrObjCMessage(CE, state), LC);
 
       // Then handle everything else.
       unsigned oldSize = Dst.size();
       SaveOr OldHasGen(Builder.hasGeneratedNode);
       
       // Dispatch to transfer function logic to handle the rest of the call.
-      Eng.getTF().evalCall(Dst, Eng, Builder, CE, L, Pred);
+      //Eng.getTF().evalCall(Dst, Eng, Builder, CE, L, Pred);
       
       // Handle the case where no nodes where generated.  Auto-generate that
       // contains the updated state if we aren't generating sinks.

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp?rev=138718&r1=138717&r2=138718&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp Sun Aug 28 00:16:28 2011
@@ -273,7 +273,12 @@
   // Bind the return value.
   state = state->BindExpr(currentStmt, ReturnValue);
 
+  // Invalidate the arguments (and the receiver)
+  const LocationContext *LC = Pred->getLocationContext();
+  state = invalidateArguments(state, CallOrObjCMessage(msg, state), LC);
+  Builder->MakeNode(Dst, msg.getOriginExpr(), Pred, state);
+
   // Now we can handle the other aspects of the message.
-  getTF().evalObjCMessage(Dst, *this, *Builder, msg, Pred, state);
+  //getTF().evalObjCMessage(Dst, *this, *Builder, msg, Pred, state);
 }
 

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ObjCMessage.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ObjCMessage.cpp?rev=138718&r1=138717&r2=138718&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ObjCMessage.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ObjCMessage.cpp Sun Aug 28 00:16:28 2011
@@ -150,3 +150,9 @@
     cast<CXXMemberCallExpr>(ActualCall)->getImplicitObjectArgument();
   return State->getSVal(callee);  
 }
+
+SVal
+CallOrObjCMessage::getInstanceMessageReceiver(const LocationContext *LC) const {
+  assert(isObjCMessage());
+  return Msg.getInstanceReceiverSVal(State, LC);
+}





More information about the cfe-commits mailing list