From: Ted Kremenek Date: Tue, 2 Mar 2010 21:43:54 +0000 (+0000) Subject: [CFG] X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5ba290a12fb9390a77ea4dca3d98deb53022d182;p=clang [CFG] 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 --- diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index d4f64bc178..d7072f0bf5 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -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. diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp index bdc0e7c621..7a628642dc 100644 --- a/lib/Analysis/UninitializedValues.cpp +++ b/lib/Analysis/UninitializedValues.cpp @@ -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(*I); if (VD && VD->isBlockVarDecl()) { - if (Stmt* I = VD->getInit()) - V(VD,AD) = AD.FullUninitTaint ? V(cast(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: // diff --git a/lib/Checker/BasicStore.cpp b/lib/Checker/BasicStore.cpp index 3661ae18fa..d93a6658c6 100644 --- a/lib/Checker/BasicStore.cpp +++ b/lib/Checker/BasicStore.cpp @@ -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(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(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(R); - if (!Val) - break; + if (Val) + return CastRetrievedVal(*Val, TR, T); - return CastRetrievedVal(*Val, cast(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(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; }