diff options
-rw-r--r-- | include/clang/Analysis/CFG.h | 112 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/GRCoreEngine.h | 3 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/GRExprEngine.h | 18 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/GRSubEngine.h | 2 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/SVals.h | 3 | ||||
-rw-r--r-- | include/clang/Analysis/ProgramPoint.h | 10 | ||||
-rw-r--r-- | lib/Analysis/CFG.cpp | 126 | ||||
-rw-r--r-- | lib/Analysis/CheckDeadStores.cpp | 20 | ||||
-rw-r--r-- | lib/Analysis/GRCoreEngine.cpp | 8 | ||||
-rw-r--r-- | lib/Analysis/GRExprEngine.cpp | 79 | ||||
-rw-r--r-- | lib/Analysis/RegionStore.cpp | 8 | ||||
-rw-r--r-- | lib/Analysis/Store.cpp | 14 | ||||
-rw-r--r-- | test/Analysis/dead-stores.cpp | 41 |
13 files changed, 303 insertions, 141 deletions
diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h index e6f4cf961b..cf9b0a0e04 100644 --- a/include/clang/Analysis/CFG.h +++ b/include/clang/Analysis/CFG.h @@ -15,8 +15,10 @@ #ifndef LLVM_CLANG_CFG_H #define LLVM_CLANG_CFG_H +#include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/GraphTraits.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/Casting.h" #include "clang/Analysis/Support/BumpVector.h" #include <cassert> @@ -31,6 +33,17 @@ namespace clang { class LangOptions; class ASTContext; +/// CFGElement - Represents a top-level expression in a basic block. +class CFGElement { + llvm::PointerIntPair<Stmt *, 1> Data; +public: + explicit CFGElement() {} + CFGElement(Stmt *S, bool lvalue) : Data(S, lvalue ? 1 : 0) {} + Stmt *getStmt() const { return Data.getPointer(); } + bool asLValue() const { return Data.getInt() == 1; } + operator Stmt*() const { return getStmt(); } +}; + /// CFGBlock - Represents a single basic block in a source-level CFG. /// It consists of: /// @@ -57,7 +70,7 @@ namespace clang { /// class CFGBlock { class StatementList { - typedef BumpVector<Stmt*> ImplTy; + typedef BumpVector<CFGElement> ImplTy; ImplTy Impl; public: StatementList(BumpVectorContext &C) : Impl(C, 4) {} @@ -67,9 +80,9 @@ class CFGBlock { typedef ImplTy::iterator reverse_iterator; typedef ImplTy::const_iterator const_reverse_iterator; - void push_back(Stmt *s, BumpVectorContext &C) { Impl.push_back(s, C); } - Stmt *front() const { return Impl.back(); } - Stmt *back() const { return Impl.front(); } + void push_back(CFGElement e, BumpVectorContext &C) { Impl.push_back(e, C); } + CFGElement front() const { return Impl.back(); } + CFGElement back() const { return Impl.front(); } iterator begin() { return Impl.rbegin(); } iterator end() { return Impl.rend(); } @@ -80,7 +93,7 @@ class CFGBlock { const_reverse_iterator rbegin() const { return Impl.begin(); } const_reverse_iterator rend() const { return Impl.end(); } - Stmt* operator[](size_t i) const { + CFGElement operator[](size_t i) const { assert(i < Impl.size()); return Impl[Impl.size() - 1 - i]; } @@ -129,8 +142,8 @@ public: typedef StatementList::reverse_iterator reverse_iterator; typedef StatementList::const_reverse_iterator const_reverse_iterator; - Stmt* front() const { return Stmts.front(); } - Stmt* back() const { return Stmts.back(); } + CFGElement front() const { return Stmts.front(); } + CFGElement back() const { return Stmts.back(); } iterator begin() { return Stmts.begin(); } iterator end() { return Stmts.end(); } @@ -145,8 +158,7 @@ public: unsigned size() const { return Stmts.size(); } bool empty() const { return Stmts.empty(); } - Stmt* operator[](size_t i) const { return Stmts[i]; } - + CFGElement operator[](size_t i) const { return Stmts[i]; } // CFG iterators typedef AdjacentBlocks::iterator pred_iterator; @@ -221,8 +233,8 @@ public: Succs.push_back(Block, C); } - void appendStmt(Stmt* Statement, BumpVectorContext &C) { - Stmts.push_back(Statement, C); + void appendStmt(Stmt* Statement, BumpVectorContext &C, bool asLValue) { + Stmts.push_back(CFGElement(Statement, asLValue), C); } }; @@ -370,13 +382,25 @@ private: namespace llvm { +/// Implement simplify_type for CFGElement, so that we can dyn_cast from +/// CFGElement to a specific Stmt class. +template <> struct simplify_type<const ::clang::CFGElement> { + typedef ::clang::Stmt* SimpleType; + static SimpleType getSimplifiedValue(const ::clang::CFGElement &Val) { + return Val.getStmt(); + } +}; + +template <> struct simplify_type< ::clang::CFGElement> + : public simplify_type<const ::clang::CFGElement> {}; + // Traits for: CFGBlock -template <> struct GraphTraits<clang::CFGBlock* > { - typedef clang::CFGBlock NodeType; - typedef clang::CFGBlock::succ_iterator ChildIteratorType; +template <> struct GraphTraits< ::clang::CFGBlock* > { + typedef ::clang::CFGBlock NodeType; + typedef ::clang::CFGBlock::succ_iterator ChildIteratorType; - static NodeType* getEntryNode(clang::CFGBlock* BB) + static NodeType* getEntryNode(::clang::CFGBlock* BB) { return BB; } static inline ChildIteratorType child_begin(NodeType* N) @@ -386,9 +410,9 @@ template <> struct GraphTraits<clang::CFGBlock* > { { return N->succ_end(); } }; -template <> struct GraphTraits<const clang::CFGBlock* > { - typedef const clang::CFGBlock NodeType; - typedef clang::CFGBlock::const_succ_iterator ChildIteratorType; +template <> struct GraphTraits< const ::clang::CFGBlock* > { + typedef const ::clang::CFGBlock NodeType; + typedef ::clang::CFGBlock::const_succ_iterator ChildIteratorType; static NodeType* getEntryNode(const clang::CFGBlock* BB) { return BB; } @@ -400,11 +424,11 @@ template <> struct GraphTraits<const clang::CFGBlock* > { { return N->succ_end(); } }; -template <> struct GraphTraits<Inverse<const clang::CFGBlock*> > { - typedef const clang::CFGBlock NodeType; - typedef clang::CFGBlock::const_pred_iterator ChildIteratorType; +template <> struct GraphTraits<Inverse<const ::clang::CFGBlock*> > { + typedef const ::clang::CFGBlock NodeType; + typedef ::clang::CFGBlock::const_pred_iterator ChildIteratorType; - static NodeType *getEntryNode(Inverse<const clang::CFGBlock*> G) + static NodeType *getEntryNode(Inverse<const ::clang::CFGBlock*> G) { return G.Graph; } static inline ChildIteratorType child_begin(NodeType* N) @@ -416,36 +440,40 @@ template <> struct GraphTraits<Inverse<const clang::CFGBlock*> > { // Traits for: CFG -template <> struct GraphTraits<clang::CFG* > - : public GraphTraits<clang::CFGBlock* > { +template <> struct GraphTraits< ::clang::CFG* > + : public GraphTraits< ::clang::CFGBlock* > { - typedef clang::CFG::iterator nodes_iterator; + typedef ::clang::CFG::iterator nodes_iterator; - static NodeType *getEntryNode(clang::CFG* F) { return &F->getEntry(); } - static nodes_iterator nodes_begin(clang::CFG* F) { return F->begin(); } - static nodes_iterator nodes_end(clang::CFG* F) { return F->end(); } + static NodeType *getEntryNode(::clang::CFG* F) { return &F->getEntry(); } + static nodes_iterator nodes_begin(::clang::CFG* F) { return F->begin(); } + static nodes_iterator nodes_end(::clang::CFG* F) { return F->end(); } }; -template <> struct GraphTraits< const clang::CFG* > - : public GraphTraits< const clang::CFGBlock* > { +template <> struct GraphTraits<const ::clang::CFG* > + : public GraphTraits<const ::clang::CFGBlock* > { - typedef clang::CFG::const_iterator nodes_iterator; + typedef ::clang::CFG::const_iterator nodes_iterator; - static NodeType *getEntryNode( const clang::CFG* F) { return &F->getEntry(); } - static nodes_iterator nodes_begin( const clang::CFG* F) { return F->begin(); } - static nodes_iterator nodes_end( const clang::CFG* F) { return F->end(); } + static NodeType *getEntryNode( const ::clang::CFG* F) { + return &F->getEntry(); + } + static nodes_iterator nodes_begin( const ::clang::CFG* F) { + return F->begin(); + } + static nodes_iterator nodes_end( const ::clang::CFG* F) { + return F->end(); + } }; -template <> struct GraphTraits<Inverse<const clang::CFG*> > - : public GraphTraits<Inverse<const clang::CFGBlock*> > { +template <> struct GraphTraits<Inverse<const ::clang::CFG*> > + : public GraphTraits<Inverse<const ::clang::CFGBlock*> > { - typedef clang::CFG::const_iterator nodes_iterator; + typedef ::clang::CFG::const_iterator nodes_iterator; - static NodeType *getEntryNode(const clang::CFG* F) { return &F->getExit(); } - static nodes_iterator nodes_begin(const clang::CFG* F) { return F->begin();} - static nodes_iterator nodes_end(const clang::CFG* F) { return F->end(); } + static NodeType *getEntryNode(const ::clang::CFG* F) { return &F->getExit(); } + static nodes_iterator nodes_begin(const ::clang::CFG* F) { return F->begin();} + static nodes_iterator nodes_end(const ::clang::CFG* F) { return F->end(); } }; - } // end llvm namespace - #endif diff --git a/include/clang/Analysis/PathSensitive/GRCoreEngine.h b/include/clang/Analysis/PathSensitive/GRCoreEngine.h index b78cc6adfc..e2a03a21eb 100644 --- a/include/clang/Analysis/PathSensitive/GRCoreEngine.h +++ b/include/clang/Analysis/PathSensitive/GRCoreEngine.h @@ -75,8 +75,7 @@ class GRCoreEngine { void ProcessEndPath(GREndPathNodeBuilder& Builder); - void ProcessStmt(Stmt* S, GRStmtNodeBuilder& Builder); - + void ProcessStmt(CFGElement E, GRStmtNodeBuilder& Builder); bool ProcessBlockEntrance(CFGBlock* Blk, const GRState* State, GRBlockCounter BC); diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h index 8b20a823c6..d4e8f79eb5 100644 --- a/include/clang/Analysis/PathSensitive/GRExprEngine.h +++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h @@ -149,7 +149,7 @@ public: /// ProcessStmt - Called by GRCoreEngine. Used to generate new successor /// nodes by processing the 'effects' of a block-level statement. - void ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder); + void ProcessStmt(CFGElement E, GRStmtNodeBuilder& builder); /// ProcessBlockEntrance - Called by GRCoreEngine when start processing /// a CFGBlock. This method returns true if the analysis should continue @@ -399,15 +399,19 @@ public: // FIXME: 'tag' should be removed, and a LocationContext should be used // instead. - void EvalLocation(ExplodedNodeSet &Dst, Stmt *S, ExplodedNode* Pred, - const GRState* St, SVal location, - const void *tag, bool isLoad); - - // FIXME: 'tag' should be removed, and a LocationContext should be used - // instead. void EvalStore(ExplodedNodeSet& Dst, Expr* AssignE, Expr* StoreE, ExplodedNode* Pred, const GRState* St, SVal TargetLV, SVal Val, const void *tag = 0); +private: + void EvalLoadCommon(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred, + const GRState* St, SVal location, const void *tag, + QualType LoadTy); + + // FIXME: 'tag' should be removed, and a LocationContext should be used + // instead. + void EvalLocation(ExplodedNodeSet &Dst, Stmt *S, ExplodedNode* Pred, + const GRState* St, SVal location, + const void *tag, bool isLoad); }; } // end clang namespace diff --git a/include/clang/Analysis/PathSensitive/GRSubEngine.h b/include/clang/Analysis/PathSensitive/GRSubEngine.h index 62e36f9e64..99cdf15e69 100644 --- a/include/clang/Analysis/PathSensitive/GRSubEngine.h +++ b/include/clang/Analysis/PathSensitive/GRSubEngine.h @@ -37,7 +37,7 @@ public: /// ProcessStmt - Called by GRCoreEngine. Used to generate new successor /// nodes by processing the 'effects' of a block-level statement. - virtual void ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) = 0; + virtual void ProcessStmt(CFGElement E, GRStmtNodeBuilder& builder) = 0; /// ProcessBlockEntrance - Called by GRCoreEngine when start processing /// a CFGBlock. This method returns true if the analysis should continue diff --git a/include/clang/Analysis/PathSensitive/SVals.h b/include/clang/Analysis/PathSensitive/SVals.h index 8b5cf40e29..3cd4f1c550 100644 --- a/include/clang/Analysis/PathSensitive/SVals.h +++ b/include/clang/Analysis/PathSensitive/SVals.h @@ -244,7 +244,8 @@ public: } static inline bool IsLocType(QualType T) { - return T->isAnyPointerType() || T->isBlockPointerType(); + return T->isAnyPointerType() || T->isBlockPointerType() || + T->isReferenceType(); } }; diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h index 5abe1abd5d..332f9d384f 100644 --- a/include/clang/Analysis/ProgramPoint.h +++ b/include/clang/Analysis/ProgramPoint.h @@ -108,9 +108,13 @@ public: return const_cast<CFGBlock*>(reinterpret_cast<const CFGBlock*>(getData1())); } - Stmt* getFirstStmt() const { + CFGElement getFirstElement() const { const CFGBlock* B = getBlock(); - return B->empty() ? NULL : B->front(); + return B->empty() ? CFGElement() : B->front(); + } + + Stmt *getFirstStmt() const { + return getFirstElement().getStmt(); } static bool classof(const ProgramPoint* Location) { @@ -129,7 +133,7 @@ public: Stmt* getLastStmt() const { const CFGBlock* B = getBlock(); - return B->empty() ? NULL : B->back(); + return B->empty() ? CFGElement() : B->back(); } Stmt* getTerminator() const { diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index e1a1e72c20..884188acd7 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -34,6 +34,17 @@ static SourceLocation GetEndLoc(Decl* D) { return D->getLocation(); } + +class AddStmtChoice { +public: + enum Kind { NotAlwaysAdd = 0, AlwaysAdd, AlwaysAddAsLValue }; +public: + AddStmtChoice(Kind kind) : k(kind) {} + bool alwaysAdd() const { return k != NotAlwaysAdd; } + bool asLValue() const { return k == AlwaysAddAsLValue; } +private: + Kind k; +}; /// CFGBuilder - This class implements CFG construction from an AST. /// The builder is stateful: an instance of the builder should be used to only @@ -84,15 +95,16 @@ public: private: // Visitors to walk an AST and construct the CFG. - CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, bool alwaysAdd); - CFGBlock *VisitBinaryOperator(BinaryOperator *B, bool alwaysAdd); - CFGBlock *VisitBlockExpr(BlockExpr* E, bool alwaysAdd); + CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, AddStmtChoice asc); + CFGBlock *VisitBinaryOperator(BinaryOperator *B, AddStmtChoice asc); + CFGBlock *VisitBlockExpr(BlockExpr* E, AddStmtChoice asc); CFGBlock *VisitBreakStmt(BreakStmt *B); - CFGBlock *VisitCallExpr(CallExpr *C, bool alwaysAdd); + CFGBlock *VisitCallExpr(CallExpr *C, AddStmtChoice asc); CFGBlock *VisitCaseStmt(CaseStmt *C); - CFGBlock *VisitChooseExpr(ChooseExpr *C); + CFGBlock *VisitChooseExpr(ChooseExpr *C, AddStmtChoice asc); CFGBlock *VisitCompoundStmt(CompoundStmt *C); - CFGBlock *VisitConditionalOperator(ConditionalOperator *C); + CFGBlock *VisitConditionalOperator(ConditionalOperator *C, + AddStmtChoice asc); CFGBlock *VisitContinueStmt(ContinueStmt *C); CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S) { return NYS(); } CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T); @@ -112,13 +124,13 @@ private: CFGBlock *VisitObjCAtTryStmt(ObjCAtTryStmt *S); CFGBlock *VisitObjCForCollectionStmt(ObjCForCollectionStmt *S); CFGBlock *VisitReturnStmt(ReturnStmt* R); - CFGBlock *VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E, bool alwaysAdd); - CFGBlock *VisitStmtExpr(StmtExpr *S, bool alwaysAdd); + CFGBlock *VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E, AddStmtChoice asc); + CFGBlock *VisitStmtExpr(StmtExpr *S, AddStmtChoice asc); CFGBlock *VisitSwitchStmt(SwitchStmt *S); CFGBlock *VisitWhileStmt(WhileStmt *W); - CFGBlock *Visit(Stmt *S, bool alwaysAdd = false); - CFGBlock *VisitStmt(Stmt *S, bool alwaysAdd); + CFGBlock *Visit(Stmt *S, AddStmtChoice asc = AddStmtChoice::NotAlwaysAdd); + CFGBlock *VisitStmt(Stmt *S, AddStmtChoice asc); CFGBlock *VisitChildren(Stmt* S); // NYS == Not Yet Supported @@ -130,10 +142,13 @@ private: void autoCreateBlock() { if (!Block) Block = createBlock(); } CFGBlock *createBlock(bool add_successor = true); bool FinishBlock(CFGBlock* B); - CFGBlock *addStmt(Stmt *S) { return Visit(S, true); } + CFGBlock *addStmt(Stmt *S, AddStmtChoice asc = AddStmtChoice::AlwaysAdd) { + return Visit(S, asc); + } - void AppendStmt(CFGBlock *B, Stmt *S) { - B->appendStmt(S, cfg->getBumpVectorContext()); + void AppendStmt(CFGBlock *B, Stmt *S, + AddStmtChoice asc = AddStmtChoice::AlwaysAdd) { + B->appendStmt(S, cfg->getBumpVectorContext(), asc.asLValue()); } void AddSuccessor(CFGBlock *B, CFGBlock *S) { @@ -278,38 +293,38 @@ bool CFGBuilder::FinishBlock(CFGBlock* B) { /// Visit - Walk the subtree of a statement and add extra /// blocks for ternary operators, &&, and ||. We also process "," and /// DeclStmts (which may contain nested control-flow). -CFGBlock* CFGBuilder::Visit(Stmt * S, bool alwaysAdd) { +CFGBlock* CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) { tryAgain: switch (S->getStmtClass()) { default: - return VisitStmt(S, alwaysAdd); + return VisitStmt(S, asc); case Stmt::AddrLabelExprClass: - return VisitAddrLabelExpr(cast<AddrLabelExpr>(S), alwaysAdd); + return VisitAddrLabelExpr(cast<AddrLabelExpr>(S), asc); case Stmt::BinaryOperatorClass: - return VisitBinaryOperator(cast<BinaryOperator>(S), alwaysAdd); + return VisitBinaryOperator(cast<BinaryOperator>(S), asc); case Stmt::BlockExprClass: - return VisitBlockExpr(cast<BlockExpr>(S), alwaysAdd); + return VisitBlockExpr(cast<BlockExpr>(S), asc); case Stmt::BreakStmtClass: return VisitBreakStmt(cast<BreakStmt>(S)); case Stmt::CallExprClass: - return VisitCallExpr(cast<CallExpr>(S), alwaysAdd); + return VisitCallExpr(cast<CallExpr>(S), asc); case Stmt::CaseStmtClass: return VisitCaseStmt(cast<CaseStmt>(S)); case Stmt::ChooseExprClass: - return VisitChooseExpr(cast<ChooseExpr>(S)); + return VisitChooseExpr(cast<ChooseExpr>(S), asc); case Stmt::CompoundStmtClass: return VisitCompoundStmt(cast<CompoundStmt>(S)); case Stmt::ConditionalOperatorClass: - return VisitConditionalOperator(cast<ConditionalOperator>(S)); + return VisitConditionalOperator(cast<ConditionalOperator>(S), asc); case Stmt::ContinueStmtClass: return VisitContinueStmt(cast<ContinueStmt>(S)); @@ -367,10 +382,10 @@ tryAgain: return VisitReturnStmt(cast<ReturnStmt>(S)); case Stmt::SizeOfAlignOfExprClass: - return VisitSizeOfAlignOfExpr(cast<SizeOfAlignOfExpr>(S), alwaysAdd); + return VisitSizeOfAlignOfExpr(cast<SizeOfAlignOfExpr>(S), asc); case Stmt::StmtExprClass: - return VisitStmtExpr(cast<StmtExpr>(S), alwaysAdd); + return VisitStmtExpr(cast<StmtExpr>(S), asc); case Stmt::SwitchStmtClass: return VisitSwitchStmt(cast<SwitchStmt>(S)); @@ -380,10 +395,10 @@ tryAgain: } } -CFGBlock *CFGBuilder::VisitStmt(Stmt *S, bool alwaysAdd) { - if (alwaysAdd) { +CFGBlock *CFGBuilder::VisitStmt(Stmt *S, AddStmtChoice asc) { + if (asc.alwaysAdd()) { autoCreateBlock(); - AppendStmt(Block, S); + AppendStmt(Block, S, asc); } return VisitChildren(S); @@ -399,21 +414,23 @@ CFGBlock *CFGBuilder::VisitChildren(Stmt* Terminator) { return B; } -CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A, bool alwaysAdd) { +CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A, + AddStmtChoice asc) { AddressTakenLabels.insert(A->getLabel()); - if (alwaysAdd) { + if (asc.alwaysAdd()) { autoCreateBlock(); - AppendStmt(Block, A); + AppendStmt(Block, A, asc); } return Block; } -CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, bool alwaysAdd) { +CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, + AddStmtChoice asc) { if (B->isLogicalOp()) { // && or || CFGBlock* ConfluenceBlock = Block ? Block : createBlock(); - AppendStmt(ConfluenceBlock, B); + AppendStmt(ConfluenceBlock, B, asc); if (!FinishBlock(ConfluenceBlock)) return 0; @@ -450,18 +467,18 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, bool alwaysAdd) { } else if (B->getOpcode() == BinaryOperator::Comma) { // , autoCreateBlock(); - AppendStmt(Block, B); + AppendStmt(Block, B, asc); addStmt(B->getRHS()); return addStmt(B->getLHS()); } - return VisitStmt(B, alwaysAdd); + return VisitStmt(B, asc); } -CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, bool alwaysAdd) { - if (alwaysAdd) { +CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, AddStmtChoice asc) { + if (asc.alwaysAdd()) { autoCreateBlock(); - AppendStmt(Block, E); + AppendStmt(Block, E, asc); } return Block; } @@ -487,7 +504,7 @@ CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) { return Block; } -CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, bool alwaysAdd) { +CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) { // If this is a call to a no-return function, this stops the block here. bool NoReturn = false; if (C->getCallee()->getType().getNoReturnAttr()) { @@ -499,14 +516,14 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, bool alwaysAdd) { NoReturn = true; if (!NoReturn) - return VisitStmt(C, alwaysAdd); + return VisitStmt(C, asc); if (Block && !FinishBlock(Block)) return 0; // Create new block with no successor for the remaining pieces. Block = createBlock(false); - AppendStmt(Block, C); + AppendStmt(Block, C, asc); // Wire this to the exit block directly. AddSuccessor(Block, &cfg->getExit()); @@ -514,9 +531,10 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, bool alwaysAdd) { return VisitChildren(C); } -CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C) { +CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C, + AddStmtChoice asc) { CFGBlock* ConfluenceBlock = Block ? Block : createBlock(); - AppendStmt(ConfluenceBlock, C); + AppendStmt(ConfluenceBlock, C, asc); if (!FinishBlock(ConfluenceBlock)) return 0; @@ -555,11 +573,12 @@ CFGBlock* CFGBuilder::VisitCompoundStmt(CompoundStmt* C) { return LastBlock; } -CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C) { +CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C, + AddStmtChoice asc) { // Create the confluence block that will "merge" the results of the ternary // expression. CFGBlock* ConfluenceBlock = Block ? Block : createBlock(); - AppendStmt(ConfluenceBlock, C); + AppendStmt(ConfluenceBlock, C, asc); if (!FinishBlock(ConfluenceBlock)) return 0; @@ -670,7 +689,10 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(Decl* D) { case Stmt::StringLiteralClass: break; default: - Block = addStmt(Init); + Block = addStmt(Init, + VD->getType()->isReferenceType() + ? AddStmtChoice::AlwaysAddAsLValue + : AddStmtChoice::AlwaysAdd); } } @@ -776,7 +798,7 @@ CFGBlock* CFGBuilder::VisitReturnStmt(ReturnStmt* R) { // Add the return statement to the block. This may create new blocks if R // contains control-flow (short-circuit operations). - return VisitStmt(R, true); + return VisitStmt(R, AddStmtChoice::AlwaysAdd); } CFGBlock* CFGBuilder::VisitLabelStmt(LabelStmt* L) { @@ -1000,7 +1022,7 @@ CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { // Walk the 'element' expression to see if there are any side-effects. We // generate new blocks as necesary. We DON'T add the statement by default to // the CFG unless it contains control-flow. - EntryConditionBlock = Visit(S->getElement(), false); + EntryConditionBlock = Visit(S->getElement(), AddStmtChoice::NotAlwaysAdd); if (Block) { if (!FinishBlock(EntryConditionBlock)) return 0; @@ -1182,7 +1204,7 @@ CFGBlock* CFGBuilder::VisitObjCAtThrowStmt(ObjCAtThrowStmt* S) { // Add the statement to the block. This may create new blocks if S contains // control-flow (short-circuit operations). - return VisitStmt(S, true); + return VisitStmt(S, AddStmtChoice::AlwaysAdd); } CFGBlock* CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr* T) { @@ -1198,7 +1220,7 @@ CFGBlock* CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr* T) { // Add the statement to the block. This may create new blocks if S contains // control-flow (short-circuit operations). - return VisitStmt(T, true); + return VisitStmt(T, AddStmtChoice::AlwaysAdd); } CFGBlock *CFGBuilder::VisitDoStmt(DoStmt* D) { @@ -1316,9 +1338,9 @@ CFGBlock* CFGBuilder::VisitContinueStmt(ContinueStmt* C) { } CFGBlock *CFGBuilder::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E, - bool alwaysAdd) { + AddStmtChoice asc) { - if (alwaysAdd) { + if (asc.alwaysAdd()) { autoCreateBlock(); AppendStmt(Block, E); } @@ -1335,8 +1357,8 @@ CFGBlock *CFGBuilder::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E, /// VisitStmtExpr - Utility method to handle (nested) statement /// expressions (a GCC extension). -CFGBlock* CFGBuilder::VisitStmtExpr(StmtExpr *SE, bool alwaysAdd) { - if (alwaysAdd) { +CFGBlock* CFGBuilder::VisitStmtExpr(StmtExpr *SE, AddStmtChoice asc) { + if (asc.alwaysAdd()) { autoCreateBlock(); AppendStmt(Block, SE); } diff --git a/lib/Analysis/CheckDeadStores.cpp b/lib/Analysis/CheckDeadStores.cpp index db9016fa1e..f081c69c2b 100644 --- a/lib/Analysis/CheckDeadStores.cpp +++ b/lib/Analysis/CheckDeadStores.cpp @@ -84,7 +84,14 @@ public: const LiveVariables::AnalysisDataTy& AD, const LiveVariables::ValTy& Live) { - if (VD->hasLocalStorage() && !Live(VD, AD) && + if (!VD->hasLocalStorage()) + return; + // Reference types confuse the dead stores checker. Skip them + // for now. + if (VD->getType()->getAs<ReferenceType>()) + return; + + if (!Live(VD, AD) && !(VD->getAttr<UnusedAttr>() || VD->getAttr<BlocksAttr>())) Report(VD, dsk, Ex->getSourceRange().getBegin(), Val->getSourceRange()); @@ -93,7 +100,6 @@ public: void CheckDeclRef(DeclRefExpr* DR, Expr* Val, DeadStoreKind dsk, const LiveVariables::AnalysisDataTy& AD, const LiveVariables::ValTy& Live) { - if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl())) CheckVarDecl(VD, DR, Val, dsk, AD, Live); } @@ -183,8 +189,13 @@ public: if (!V) continue; - - if (V->hasLocalStorage()) + + if (V->hasLocalStorage()) { + // Reference types confuse the dead stores checker. Skip them + // for now. + if (V->getType()->getAs<ReferenceType>()) + return; + if (Expr* E = V->getInit()) { // Don't warn on C++ objects (yet) until we can show that their // constructors/destructors don't have side effects. @@ -218,6 +229,7 @@ public: Report(V, DeadInit, V->getLocation(), E->getSourceRange()); } } + } } } }; diff --git a/lib/Analysis/GRCoreEngine.cpp b/lib/Analysis/GRCoreEngine.cpp index 644dd199be..1c05ddc60b 100644 --- a/lib/Analysis/GRCoreEngine.cpp +++ b/lib/Analysis/GRCoreEngine.cpp @@ -122,8 +122,8 @@ void GRCoreEngine::ProcessEndPath(GREndPathNodeBuilder& Builder) { SubEngine.ProcessEndPath(Builder); } -void GRCoreEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& Builder) { - SubEngine.ProcessStmt(S, Builder); +void GRCoreEngine::ProcessStmt(CFGElement E, GRStmtNodeBuilder& Builder) { + SubEngine.ProcessStmt(E, Builder); } bool GRCoreEngine::ProcessBlockEntrance(CFGBlock* Blk, const GRState* State, @@ -241,10 +241,10 @@ void GRCoreEngine::HandleBlockEntrance(const BlockEntrance& L, WList->setBlockCounter(Counter); // Process the entrance of the block. - if (Stmt* S = L.getFirstStmt()) { + if (CFGElement E = L.getFirstElement()) { GRStmtNodeBuilder Builder(L.getBlock(), 0, Pred, this, SubEngine.getStateManager()); - ProcessStmt(S, Builder); + ProcessStmt(E, Builder); } else HandleBlockExit(L.getBlock(), Pred); diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index 51e6a54752..a0ec87d2f7 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -33,6 +33,7 @@ using namespace clang; using llvm::dyn_cast; +using llvm::dyn_cast_or_null; using llvm::cast; using llvm::APSInt; @@ -378,17 +379,15 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) { // Top-level transfer function logic (Dispatcher). //===----------------------------------------------------------------------===// -void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) { - +void GRExprEngine::ProcessStmt(CFGElement CE, GRStmtNodeBuilder& builder) { + CurrentStmt = CE.getStmt(); PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), - S->getLocStart(), + CurrentStmt->getLocStart(), "Error evaluating statement"); Builder = &builder; EntryNode = builder.getLastNode(); - CurrentStmt = S; - // Set up our simple checks. if (BatchAuditor) Builder->setAuditor(BatchAuditor.get()); @@ -415,7 +414,7 @@ void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) { // FIXME: This should soon be removed. ExplodedNodeSet Tmp2; - getTF().EvalDeadSymbols(Tmp2, *this, *Builder, EntryNode, S, + getTF().EvalDeadSymbols(Tmp2, *this, *Builder, EntryNode, CurrentStmt, CleanedState, SymReaper); if (Checkers.empty()) @@ -437,8 +436,8 @@ void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) { Checker *checker = I->second; for (ExplodedNodeSet::iterator NI = SrcSet->begin(), NE = SrcSet->end(); NI != NE; ++NI) - checker->GR_EvalDeadSymbols(*DstSet, *Builder, *this, S, *NI, - SymReaper, tag); + checker->GR_EvalDeadSymbols(*DstSet, *Builder, *this, CurrentStmt, + *NI, SymReaper, tag); SrcSet = DstSet; } } @@ -457,7 +456,10 @@ void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) { Builder->SetCleanedState(*I == EntryNode ? CleanedState : GetState(*I)); // Visit the statement. - Visit(S, *I, Dst); + if (CE.asLValue()) + VisitLValue(cast<Expr>(CurrentStmt), *I, Dst); + else + Visit(CurrentStmt, *I, Dst); // Do we need to auto-generate a node? We only need to do this to generate // a node with a "cleaned" state; GRCoreEngine will actually handle @@ -465,7 +467,7 @@ void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) { if (Dst.size() == 1 && *Dst.begin() == EntryNode && !Builder->HasGeneratedNode && !HasAutoGenerated) { HasAutoGenerated = true; - builder.generateNode(S, GetState(EntryNode), *I); + builder.generateNode(CurrentStmt, GetState(EntryNode), *I); } } @@ -1232,13 +1234,23 @@ void GRExprEngine::VisitCommonDeclRefExpr(Expr *Ex, const NamedDecl *D, SVal V = state->getLValue(VD, Pred->getLocationContext()); - if (asLValue) - MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V), - ProgramPoint::PostLValueKind); + if (asLValue) { + // For references, the 'lvalue' is the pointer address stored in the + // reference region. + if (VD->getType()->isReferenceType()) { + if (const MemRegion *R = V.getAsRegion()) + V = state->getSVal(R); + else + V = UnknownVal(); + } + + MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V, + ProgramPoint::PostLValueKind)); + } else EvalLoad(Dst, Ex, Pred, state, V); - return; + return; } else if (const EnumConstantDecl* ED = dyn_cast<EnumConstantDecl>(D)) { assert(!asLValue && "EnumConstantDecl does not have lvalue."); @@ -1415,6 +1427,37 @@ void GRExprEngine::EvalLoad(ExplodedNodeSet& Dst, Expr *Ex, ExplodedNode* Pred, const GRState* state, SVal location, const void *tag, QualType LoadTy) { + // Are we loading from a region? This actually results in two loads; one + // to fetch the address of the referenced value and one to fetch the + // referenced value. + if (const TypedRegion *TR = + dyn_cast_or_null<TypedRegion>(location.getAsRegion())) { + + QualType ValTy = TR->getValueType(getContext()); + if (const ReferenceType *RT = ValTy->getAs<ReferenceType>()) { + static int load |