diff options
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/Analysis/CFG.cpp | 126 | ||||
| -rw-r--r-- | clang/lib/Analysis/CheckDeadStores.cpp | 20 | ||||
| -rw-r--r-- | clang/lib/Analysis/GRCoreEngine.cpp | 8 | ||||
| -rw-r--r-- | clang/lib/Analysis/GRExprEngine.cpp | 79 | ||||
| -rw-r--r-- | clang/lib/Analysis/RegionStore.cpp | 8 | ||||
| -rw-r--r-- | clang/lib/Analysis/Store.cpp | 14 |
6 files changed, 176 insertions, 79 deletions
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index e1a1e72c204..884188acd78 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/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/clang/lib/Analysis/CheckDeadStores.cpp b/clang/lib/Analysis/CheckDeadStores.cpp index db9016fa1e6..f081c69c2b1 100644 --- a/clang/lib/Analysis/CheckDeadStores.cpp +++ b/clang/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/clang/lib/Analysis/GRCoreEngine.cpp b/clang/lib/Analysis/GRCoreEngine.cpp index 644dd199bea..1c05ddc60bc 100644 --- a/clang/lib/Analysis/GRCoreEngine.cpp +++ b/clang/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/clang/lib/Analysis/GRExprEngine.cpp b/clang/lib/Analysis/GRExprEngine.cpp index 51e6a547529..a0ec87d2f75 100644 --- a/clang/lib/Analysis/GRExprEngine.cpp +++ b/clang/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 loadReferenceTag = 0; + ExplodedNodeSet Tmp; + EvalLoadCommon(Tmp, Ex, Pred, state, location, &loadReferenceTag, + getContext().getPointerType(RT->getPointeeType())); + + // Perform the load from the referenced value. + for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end() ; I!=E; ++I) { + state = GetState(*I); + location = state->getSVal(Ex); + EvalLoadCommon(Dst, Ex, *I, state, location, tag, LoadTy); + } + return; + } + } + + EvalLoadCommon(Dst, Ex, Pred, state, location, tag, LoadTy); +} + +void GRExprEngine::EvalLoadCommon(ExplodedNodeSet& Dst, Expr *Ex, + ExplodedNode* Pred, + const GRState* state, SVal location, + const void *tag, QualType LoadTy) { + // Evaluate the location (checks for bad dereferences). ExplodedNodeSet Tmp; EvalLocation(Tmp, Ex, Pred, state, location, tag, true); @@ -1992,8 +2035,12 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, // time a function is called those values may not be current. ExplodedNodeSet Tmp; - if (InitEx) - Visit(InitEx, Pred, Tmp); + if (InitEx) { + if (VD->getType()->isReferenceType()) + VisitLValue(InitEx, Pred, Tmp); + else + Visit(InitEx, Pred, Tmp); + } else Tmp.Add(Pred); diff --git a/clang/lib/Analysis/RegionStore.cpp b/clang/lib/Analysis/RegionStore.cpp index a96f6c85be8..bc3680e23da 100644 --- a/clang/lib/Analysis/RegionStore.cpp +++ b/clang/lib/Analysis/RegionStore.cpp @@ -1424,7 +1424,13 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) { // Binding directly to a symbolic region should be treated as binding // to element 0. QualType T = SR->getSymbol()->getType(getContext()); - T = T->getAs<PointerType>()->getPointeeType(); + + // FIXME: Is this the right way to handle symbols that are references? + if (const PointerType *PT = T->getAs<PointerType>()) + T = PT->getPointeeType(); + else + T = T->getAs<ReferenceType>()->getPointeeType(); + R = GetElementZeroRegion(SR, T); } diff --git a/clang/lib/Analysis/Store.cpp b/clang/lib/Analysis/Store.cpp index e6ff6e5af47..56f8a0a70c9 100644 --- a/clang/lib/Analysis/Store.cpp +++ b/clang/lib/Analysis/Store.cpp @@ -198,11 +198,21 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) /// as another region. SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R, QualType castTy) { + +#ifndef NDEBUG if (castTy.isNull()) return V; + + ASTContext &Ctx = ValMgr.getContext(); + QualType T = R->getValueType(Ctx); + + // Automatically translate references to pointers. + if (const ReferenceType *RT = T->getAs<ReferenceType>()) + T = Ctx.getPointerType(RT->getPointeeType()); + + assert(ValMgr.getContext().hasSameUnqualifiedType(castTy, T)); +#endif - assert(ValMgr.getContext().hasSameUnqualifiedType(castTy, - R->getValueType(ValMgr.getContext()))); return V; } |

