[cfe-commits] r129166 - in /cfe/trunk: lib/StaticAnalyzer/Core/CXXExprEngine.cpp lib/StaticAnalyzer/Core/ExprEngine.cpp test/Analysis/misc-ps-region-store.cpp

Ted Kremenek kremenek at apple.com
Fri Apr 8 15:42:35 PDT 2011


Author: kremenek
Date: Fri Apr  8 17:42:35 2011
New Revision: 129166

URL: http://llvm.org/viewvc/llvm-project?rev=129166&view=rev
Log:
Start overhauling static analyzer support for C++ constructors.  The inlining support isn't complete, and needs
to be reworked to model CallEnter/CallExit (just like all other calls).  For now, treat constructors mostly
like other function calls, making the analysis of C++ code just a little more useful.

Modified:
    cfe/trunk/lib/StaticAnalyzer/Core/CXXExprEngine.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
    cfe/trunk/test/Analysis/misc-ps-region-store.cpp

Modified: cfe/trunk/lib/StaticAnalyzer/Core/CXXExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CXXExprEngine.cpp?rev=129166&r1=129165&r2=129166&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CXXExprEngine.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CXXExprEngine.cpp Fri Apr  8 17:42:35 2011
@@ -124,53 +124,121 @@
 }
 
 void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, 
-                                         const MemRegion *Dest,
-                                         ExplodedNode *Pred,
-                                         ExplodedNodeSet &Dst) {
-  if (!Dest)
-    Dest = svalBuilder.getRegionManager().getCXXTempObjectRegion(E,
-                                                    Pred->getLocationContext());
-
-  if (E->isElidable()) {
-    VisitAggExpr(E->getArg(0), Dest, Pred, Dst);
-    // FIXME: this is here to force propogation if VisitAggExpr doesn't
-    if (Dst.empty())
-      Dst.Add(Pred);
-    return;
-  }
+                                       const MemRegion *Dest,
+                                       ExplodedNode *Pred,
+                                       ExplodedNodeSet &destNodes) {
 
   const CXXConstructorDecl *CD = E->getConstructor();
   assert(CD);
-
+  
+#if 0
   if (!(CD->isThisDeclarationADefinition() && AMgr.shouldInlineCall()))
     // FIXME: invalidate the object.
     return;
-
+#endif
   
   // Evaluate other arguments.
   ExplodedNodeSet argsEvaluated;
   const FunctionProtoType *FnType = CD->getType()->getAs<FunctionProtoType>();
   evalArguments(E->arg_begin(), E->arg_end(), FnType, Pred, argsEvaluated);
-  // The callee stack frame context used to create the 'this' parameter region.
-  const StackFrameContext *SFC = AMgr.getStackFrame(CD, 
-                                                    Pred->getLocationContext(),
-                                                    E, Builder->getBlock(),
-                                                    Builder->getIndex());
 
-  const CXXThisRegion *ThisR =getCXXThisRegion(E->getConstructor()->getParent(),
-                                               SFC);
+#if 0
+  // Is the constructor elidable?
+  if (E->isElidable()) {
+    VisitAggExpr(E->getArg(0), destNodes, Pred, Dst);
+    // FIXME: this is here to force propogation if VisitAggExpr doesn't
+    if (destNodes.empty())
+      destNodes.Add(Pred);
+    return;
+  }
+#endif
+  
+  // Perform the previsit of the constructor.
+  ExplodedNodeSet destPreVisit;
+  getCheckerManager().runCheckersForPreStmt(destPreVisit, argsEvaluated, E, 
+                                            *this);
+  
+  // Evaluate the constructor.  Currently we don't now allow checker-specific
+  // implementations of specific constructors (as we do with ordinary
+  // function calls.  We can re-evaluate this in the future.
+  
+#if 0
+  // Inlining currently isn't fully implemented.
+
+  if (AMgr.shouldInlineCall()) {
+    if (!Dest)
+      Dest =
+        svalBuilder.getRegionManager().getCXXTempObjectRegion(E,
+                                                  Pred->getLocationContext());
+
+    // The callee stack frame context used to create the 'this'
+    // parameter region.
+    const StackFrameContext *SFC = 
+      AMgr.getStackFrame(CD, Pred->getLocationContext(),
+                         E, Builder->getBlock(), Builder->getIndex());
+
+    // Create the 'this' region.
+    const CXXThisRegion *ThisR =
+      getCXXThisRegion(E->getConstructor()->getParent(), SFC);
+
+    CallEnter Loc(E, SFC, Pred->getLocationContext());
+
+
+    for (ExplodedNodeSet::iterator NI = argsEvaluated.begin(),
+                                  NE = argsEvaluated.end(); NI != NE; ++NI) {
+      const GRState *state = GetState(*NI);
+      // Setup 'this' region, so that the ctor is evaluated on the object pointed
+      // by 'Dest'.
+      state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest));
+      if (ExplodedNode *N = Builder->generateNode(Loc, state, *NI))
+        destNodes.Add(N);
+    }
+  }
+#endif
+  
+  // Default semantics: invalidate all regions passed as arguments.
+  llvm::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
+        i = destPreVisit.begin(), e = destPreVisit.end();
+       i != e; ++i)
+  {
+    ExplodedNode *Pred = *i;
+    const GRState *state = GetState(Pred);
 
-  CallEnter Loc(E, SFC, Pred->getLocationContext());
-  for (ExplodedNodeSet::iterator NI = argsEvaluated.begin(),
-                                 NE = argsEvaluated.end(); NI != NE; ++NI) {
-    const GRState *state = GetState(*NI);
-    // Setup 'this' region, so that the ctor is evaluated on the object pointed
-    // by 'Dest'.
-    state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest));
-    ExplodedNode *N = Builder->generateNode(Loc, state, Pred);
-    if (N)
-      Dst.Add(N);
+    // 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.data(),
+                                     regionsToInvalidate.data() +
+                                     regionsToInvalidate.size(),
+                                     E, blockCount, 0,
+                                     /* invalidateGlobals = */ true);
+    
+    Builder->MakeNode(destCall, E, Pred, state);
   }
+  
+  // Do the post visit.
+  getCheckerManager().runCheckersForPostStmt(destNodes, destCall, E, *this);  
 }
 
 void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD,

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=129166&r1=129165&r2=129166&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Fri Apr  8 17:42:35 2011
@@ -422,7 +422,6 @@
     // C++ stuff we don't support yet.
     case Stmt::CXXBindTemporaryExprClass:
     case Stmt::CXXCatchStmtClass:
-    case Stmt::CXXDefaultArgExprClass:
     case Stmt::CXXDependentScopeMemberExprClass:
     case Stmt::CXXNullPtrLiteralExprClass:
     case Stmt::CXXPseudoDestructorExprClass:
@@ -448,7 +447,14 @@
       Engine.addAbortedBlock(node, Builder->getBlock());
       break;
     }
-      
+    
+    // We don't handle default arguments either yet, but we can fake it
+    // for now by just skipping them.
+    case Stmt::CXXDefaultArgExprClass: {
+      Dst.Add(Pred);
+      break;
+    }
+
     case Stmt::ParenExprClass:
       llvm_unreachable("ParenExprs already handled.");
     // Cases that should never be evaluated simply because they shouldn't

Modified: cfe/trunk/test/Analysis/misc-ps-region-store.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/misc-ps-region-store.cpp?rev=129166&r1=129165&r2=129166&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/misc-ps-region-store.cpp (original)
+++ cfe/trunk/test/Analysis/misc-ps-region-store.cpp Fri Apr  8 17:42:35 2011
@@ -278,3 +278,28 @@
   return val;
 }
 
+// Test constructors invalidating arguments.  Previously this raised
+// an uninitialized value warning.
+extern "C" void __attribute__((noreturn)) PR9645_exit(int i);
+
+class PR9645_SideEffect
+{
+public:
+  PR9645_SideEffect(int *pi); // caches pi in i_
+  void Read(int *pi); // copies *pi into *i_
+private:
+  int *i_;
+};
+
+void PR9645() {
+  int i;
+
+  PR9645_SideEffect se(&i);
+  int j = 1;
+  se.Read(&j); // this has a side-effect of initializing i.
+
+  PR9645_exit(i); // no-warning
+}
+
+PR9645_SideEffect::PR9645_SideEffect(int *pi) : i_(pi) {}
+void PR9645_SideEffect::Read(int *pi) { *i_ = *pi; }





More information about the cfe-commits mailing list