]> granicus.if.org Git - clang/commitdiff
[CFG]
authorTed Kremenek <kremenek@apple.com>
Tue, 2 Mar 2010 21:43:54 +0000 (21:43 +0000)
committerTed Kremenek <kremenek@apple.com>
Tue, 2 Mar 2010 21:43:54 +0000 (21:43 +0000)
After discussion with Zhongxing, don't force the initializer of DeclStmts to be
block-level expressions.

This led to some interesting fallout:

[UninitializedValues]

Always visit the initializer of DeclStmts (do not assume they are block-level expressions).

[BasicStore]

With initializers of DeclStmts no longer block-level expressions, this causes self-referencing initializers (e.g. 'int x = x') to no longer cause the initialized variable to be live before the DeclStmt.  While this is correct, it caused BasicStore::RemoveDeadBindings() to prune off the values of these variables from the initial store (where they are set to uninitialized).  The fix is to back-port some (and only some) of the lazy-binding logic from RegionStore to
BasicStore.  Now the default values of local variables are determined lazily as opposed
to explicitly initialized.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@97591 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Analysis/CFG.cpp
lib/Analysis/UninitializedValues.cpp
lib/Checker/BasicStore.cpp

index d4f64bc17869d66c2230b6ef893314a726a7736a..d7072f0bf58dac14e28f0ee2ebbeacc9eb416a7a 100644 (file)
@@ -38,13 +38,21 @@ static SourceLocation GetEndLoc(Decl* D) {
   
 class AddStmtChoice {
 public:
-  enum Kind { NotAlwaysAdd = 0, AlwaysAdd, AlwaysAddAsLValue };
+  enum Kind { NotAlwaysAdd = 0,
+              AlwaysAdd = 1,
+              AsLValueNotAlwaysAdd = 2,
+              AlwaysAddAsLValue = 3 };
+
 public:
-  AddStmtChoice(Kind kind) : k(kind) {}  
-  bool alwaysAdd() const { return k != NotAlwaysAdd; }
-  bool asLValue() const { return k == AlwaysAddAsLValue; }
+  AddStmtChoice(Kind k)
+    : AsLValue(k >= AlwaysAddAsLValue), AlwaysAddStmt((unsigned)k & 0x1) {}
+
+  bool alwaysAdd() const { return (bool) AlwaysAddStmt; };
+  bool asLValue() const { return (bool) AsLValue; };
+
 private:
-  Kind k;
+  unsigned AsLValue : 1;
+  unsigned AlwaysAddStmt : 1;
 };
 
 /// CFGBuilder - This class implements CFG construction from an AST.
@@ -771,18 +779,10 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(Decl* D) {
   Expr *Init = VD->getInit();
 
   if (Init) {
-    // Optimization: Don't create separate block-level statements for literals.
-    switch (Init->getStmtClass()) {
-      case Stmt::IntegerLiteralClass:
-      case Stmt::CharacterLiteralClass:
-      case Stmt::StringLiteralClass:
-        break;
-      default:
-        Block = addStmt(Init,
-                        VD->getType()->isReferenceType()
-                        ? AddStmtChoice::AlwaysAddAsLValue
-                        : AddStmtChoice::AlwaysAdd);
-    }
+    AddStmtChoice::Kind k =
+      VD->getType()->isReferenceType() ? AddStmtChoice::AsLValueNotAlwaysAdd
+                                       : AddStmtChoice::NotAlwaysAdd;
+    Visit(Init, AddStmtChoice(k));
   }
 
   // If the type of VD is a VLA, then we must process its size expressions.
index bdc0e7c621f7fb6b5db47cb1b9b302c49f7ab619..7a628642dc99ea6fc4c38052293660bbb8904192 100644 (file)
@@ -134,8 +134,12 @@ bool TransferFuncs::VisitDeclStmt(DeclStmt* S) {
   for (DeclStmt::decl_iterator I=S->decl_begin(), E=S->decl_end(); I!=E; ++I) {
     VarDecl *VD = dyn_cast<VarDecl>(*I);
     if (VD && VD->isBlockVarDecl()) {
-      if (Stmt* I = VD->getInit())
-        V(VD,AD) = AD.FullUninitTaint ? V(cast<Expr>(I),AD) : Initialized;
+      if (Stmt* I = VD->getInit()) {
+        // Visit the subexpression to check for uses of uninitialized values,
+        // even if we don't propagate that value.
+        bool isSubExprUninit = Visit(I);
+        V(VD,AD) = AD.FullUninitTaint ? isSubExprUninit : Initialized;
+      }
       else {
         // Special case for declarations of array types.  For things like:
         //
index 3661ae18fab321385bca51e96cbd4336861ca60d..d93a6658c681bc7f0b8bd9c9c6db9b5a524c1e3d 100644 (file)
@@ -95,6 +95,8 @@ public:
              const char *sep);
 
 private:
+  SVal LazyRetrieve(Store store, const TypedRegion *R);
+
   ASTContext& getContext() { return StateMgr.getContext(); }
 };
 
@@ -126,6 +128,25 @@ static bool isHigherOrderRawPtr(QualType T, ASTContext &C) {
   }
 }
 
+SVal BasicStoreManager::LazyRetrieve(Store store, const TypedRegion *R) {
+  const VarRegion *VR = dyn_cast<VarRegion>(R);
+  if (!VR)
+    return UnknownVal();
+
+  const VarDecl *VD = VR->getDecl();
+  QualType T = VD->getType();
+
+  // Only handle simple types that we can symbolicate.
+  if (!SymbolManager::canSymbolicate(T) || !T->isScalarType())
+    return UnknownVal();
+
+  // Globals and parameters start with symbolic values.
+  // Local variables initially are undefined.
+  if (VR->hasGlobalsOrParametersStorage())
+    return ValMgr.getRegionValueSymbolVal(R);
+  return UndefinedVal();
+}
+
 SVal BasicStoreManager::Retrieve(Store store, Loc loc, QualType T) {
   if (isa<UnknownVal>(loc))
     return UnknownVal();
@@ -142,11 +163,13 @@ SVal BasicStoreManager::Retrieve(Store store, Loc loc, QualType T) {
 
       BindingsTy B = GetBindings(store);
       BindingsTy::data_type *Val = B.lookup(R);
+      const TypedRegion *TR = cast<TypedRegion>(R);
 
-      if (!Val)
-        break;
+      if (Val)
+        return CastRetrievedVal(*Val, TR, T);
 
-      return CastRetrievedVal(*Val, cast<TypedRegion>(R), T);
+      SVal V = LazyRetrieve(store, TR);
+      return V.isUnknownOrUndef() ? V : CastRetrievedVal(V, TR, T);
     }
 
     case loc::ConcreteIntKind:
@@ -353,8 +376,8 @@ Store BasicStoreManager::getInitialStore(const LocationContext *InitLoc) {
           // SelfRegion?  (i.e., it implements MD->getClassInterface()).
           const VarRegion *VR = MRMgr.getVarRegion(PD, InitLoc);
           const MemRegion *SelfRegion =
-            ValMgr.getRegionValueSymbolVal(VR).getAsRegion();          
-          assert(SelfRegion);          
+            ValMgr.getRegionValueSymbolVal(VR).getAsRegion();
+          assert(SelfRegion);
           St = Bind(St, ValMgr.makeLoc(VR), loc::MemRegionVal(SelfRegion));
           // Scan the method for ivar references.  While this requires an
           // entire AST scan, the cost should not be high in practice.
@@ -362,21 +385,8 @@ Store BasicStoreManager::getInitialStore(const LocationContext *InitLoc) {
         }
       }
     }
-    else if (VarDecl* VD = dyn_cast<VarDecl>(ND)) {
-      // Only handle simple types that we can symbolicate.
-      if (!SymbolManager::canSymbolicate(VD->getType()))
-        continue;
-
-      // Initialize globals and parameters to symbolic values.
-      // Initialize local variables to undefined.
-      const VarRegion *R = ValMgr.getRegionManager().getVarRegion(VD, InitLoc);
-      SVal X = UndefinedVal();
-      if (R->hasGlobalsOrParametersStorage())
-        X = ValMgr.getRegionValueSymbolVal(R);
-
-      St = Bind(St, ValMgr.makeLoc(R), X);
-    }
   }
+
   return St;
 }