diff options
Diffstat (limited to 'lib/Analysis')
-rw-r--r-- | lib/Analysis/AnalysisContext.cpp | 16 | ||||
-rw-r--r-- | lib/Analysis/BasicObjCFoundationChecks.cpp | 2 | ||||
-rw-r--r-- | lib/Analysis/BasicStore.cpp | 17 | ||||
-rw-r--r-- | lib/Analysis/CFG.cpp | 197 | ||||
-rw-r--r-- | lib/Analysis/CFRefCount.cpp | 17 | ||||
-rw-r--r-- | lib/Analysis/CallInliner.cpp | 94 | ||||
-rw-r--r-- | lib/Analysis/CheckDeadStores.cpp | 24 | ||||
-rw-r--r-- | lib/Analysis/GRCoreEngine.cpp | 14 | ||||
-rw-r--r-- | lib/Analysis/GRExprEngine.cpp | 582 | ||||
-rw-r--r-- | lib/Analysis/LiveVariables.cpp | 27 | ||||
-rw-r--r-- | lib/Analysis/MallocChecker.cpp | 32 | ||||
-rw-r--r-- | lib/Analysis/MemRegion.cpp | 18 | ||||
-rw-r--r-- | lib/Analysis/NoReturnFunctionChecker.cpp | 5 | ||||
-rw-r--r-- | lib/Analysis/OSAtomicChecker.cpp | 10 | ||||
-rw-r--r-- | lib/Analysis/RegionStore.cpp | 29 | ||||
-rw-r--r-- | lib/Analysis/SValuator.cpp | 17 | ||||
-rw-r--r-- | lib/Analysis/SimpleConstraintManager.cpp | 28 | ||||
-rw-r--r-- | lib/Analysis/Store.cpp | 21 |
18 files changed, 819 insertions, 331 deletions
diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp index 05e5196c5b971..97e6d914d450f 100644 --- a/lib/Analysis/AnalysisContext.cpp +++ b/lib/Analysis/AnalysisContext.cpp @@ -105,7 +105,7 @@ void LocationContext::ProfileCommon(llvm::FoldingSetNodeID &ID, } void StackFrameContext::Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getAnalysisContext(), getParent(), CallSite); + Profile(ID, getAnalysisContext(), getParent(), CallSite, Block, Index); } void ScopeContext::Profile(llvm::FoldingSetNodeID &ID) { @@ -145,8 +145,18 @@ LocationContextManager::getLocationContext(AnalysisContext *ctx, const StackFrameContext* LocationContextManager::getStackFrame(AnalysisContext *ctx, const LocationContext *parent, - const Stmt *s) { - return getLocationContext<StackFrameContext, Stmt>(ctx, parent, s); + const Stmt *s, const CFGBlock *blk, + unsigned idx) { + llvm::FoldingSetNodeID ID; + StackFrameContext::Profile(ID, ctx, parent, s, blk, idx); + void *InsertPos; + StackFrameContext *L = + cast_or_null<StackFrameContext>(Contexts.FindNodeOrInsertPos(ID, InsertPos)); + if (!L) { + L = new StackFrameContext(ctx, parent, s, blk, idx); + Contexts.InsertNode(L, InsertPos); + } + return L; } const ScopeContext * diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp index c913779864961..67483d9792912 100644 --- a/lib/Analysis/BasicObjCFoundationChecks.cpp +++ b/lib/Analysis/BasicObjCFoundationChecks.cpp @@ -294,7 +294,7 @@ namespace { } static Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) { - static unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 }; + static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 }; if (i < kCFNumberCharType) return FixedSize[i-1]; diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp index a38aaa7eb268c..224281b177706 100644 --- a/lib/Analysis/BasicStore.cpp +++ b/lib/Analysis/BasicStore.cpp @@ -479,15 +479,14 @@ Store BasicStoreManager::getInitialStore(const LocationContext *InitLoc) { const Decl& CD = *InitLoc->getDecl(); if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(&CD)) { if (MD->getSelfDecl() == PD) { - // FIXME: Just use a symbolic region, and remove ObjCObjectRegion - // entirely. - const ObjCObjectRegion *SelfRegion = - MRMgr.getObjCObjectRegion(MD->getClassInterface(), - MRMgr.getHeapRegion()); - - St = BindInternal(St, ValMgr.makeLoc(MRMgr.getVarRegion(PD, InitLoc)), - ValMgr.makeLoc(SelfRegion)); - + // FIXME: Add type constraints (when they become available) to + // SelfRegion? (i.e., it implements MD->getClassInterface()). + const MemRegion *VR = MRMgr.getVarRegion(PD, InitLoc); + const MemRegion *SelfRegion = + ValMgr.getRegionValueSymbolVal(VR).getAsRegion(); + assert(SelfRegion); + St = BindInternal(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. St = scanForIvars(MD->getBody(), PD, SelfRegion, St); diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index e1a1e72c20433..eab7da7e83709 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); } } @@ -754,7 +776,19 @@ CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) { // Add the condition as the last statement in the new block. This may create // new blocks as the condition may contain control-flow. Any newly created // blocks will be pointed to be "Block". - return addStmt(I->getCond()); + Block = addStmt(I->getCond()); + + // Finally, if the IfStmt contains a condition variable, add both the IfStmt + // and the condition variable initialization to the CFG. + if (VarDecl *VD = I->getConditionVariable()) { + if (Expr *Init = VD->getInit()) { + autoCreateBlock(); + AppendStmt(Block, I, AddStmtChoice::AlwaysAdd); + addStmt(Init); + } + } + + return Block; } @@ -776,7 +810,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) { @@ -854,6 +888,19 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) { if (Stmt* C = F->getCond()) { Block = ExitConditionBlock; EntryConditionBlock = addStmt(C); + assert(Block == EntryConditionBlock); + + // If this block contains a condition variable, add both the condition + // variable and initializer to the CFG. + if (VarDecl *VD = F->getConditionVariable()) { + if (Expr *Init = VD->getInit()) { + autoCreateBlock(); + AppendStmt(Block, F, AddStmtChoice::AlwaysAdd); + EntryConditionBlock = addStmt(Init); + assert(Block == EntryConditionBlock); + } + } + if (Block) { if (!FinishBlock(EntryConditionBlock)) return 0; @@ -1000,7 +1047,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; @@ -1096,6 +1143,18 @@ CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) { Block = ExitConditionBlock; EntryConditionBlock = addStmt(C); assert(Block == EntryConditionBlock); + + // If this block contains a condition variable, add both the condition + // variable and initializer to the CFG. + if (VarDecl *VD = W->getConditionVariable()) { + if (Expr *Init = VD->getInit()) { + autoCreateBlock(); + AppendStmt(Block, W, AddStmtChoice::AlwaysAdd); + EntryConditionBlock = addStmt(Init); + assert(Block == EntryConditionBlock); + } + } + if (Block) { if (!FinishBlock(EntryConditionBlock)) return 0; @@ -1182,7 +1241,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 +1257,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 +1375,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 +1394,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); } @@ -1391,8 +1450,19 @@ CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) { SwitchTerminatedBlock->setTerminator(Terminator); assert (Terminator->getCond() && "switch condition must be non-NULL"); Block = SwitchTerminatedBlock; - - return addStmt(Terminator->getCond()); + Block = addStmt(Terminator->getCond()); + + // Finally, if the SwitchStmt contains a condition variable, add both the + // SwitchStmt and the condition variable initialization to the CFG. + if (VarDecl *VD = Terminator->getConditionVariable()) { + if (Expr *Init = VD->getInit()) { + autoCreateBlock(); + AppendStmt(Block, Terminator, AddStmtChoice::AlwaysAdd); + addStmt(Init); + } + } + + return Block; } CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* CS) { @@ -1514,17 +1584,20 @@ namespace { typedef llvm::DenseMap<const Stmt*,unsigned> BlkExprMapTy; } -static void FindSubExprAssignments(Stmt* Terminator, llvm::SmallPtrSet<Expr*,50>& Set) { - if (!Terminator) +static void FindSubExprAssignments(Stmt *S, + llvm::SmallPtrSet<Expr*,50>& Set) { + if (!S) return; - for (Stmt::child_iterator I=Terminator->child_begin(), E=Terminator->child_end(); I!=E; ++I) { - if (!*I) continue; - - if (BinaryOperator* B = dyn_cast<BinaryOperator>(*I)) + for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I) { + Stmt *child = *I; + if (!child) + continue; + + if (BinaryOperator* B = dyn_cast<BinaryOperator>(child)) if (B->isAssignmentOp()) Set.insert(B); - FindSubExprAssignments(*I, Set); + FindSubExprAssignments(child, Set); } } diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index 9639ad98fa69e..a15a8f16c46f1 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -1149,7 +1149,11 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { // [PR 3337] Use 'getAs<FunctionType>' to strip away any typedefs on the // function's type. const FunctionType* FT = FD->getType()->getAs<FunctionType>(); - const char* FName = FD->getIdentifier()->getNameStart(); + const IdentifierInfo *II = FD->getIdentifier(); + if (!II) + break; + + const char* FName = II->getNameStart(); // Strip away preceding '_'. Doing this here will effect all the checks // down below. @@ -2938,6 +2942,17 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, QualType T = Ex->getType(); + // For CallExpr, use the result type to know if it returns a reference. + if (const CallExpr *CE = dyn_cast<CallExpr>(Ex)) { + const Expr *Callee = CE->getCallee(); + if (const FunctionDecl *FD = state->getSVal(Callee).getAsFunctionDecl()) + T = FD->getResultType(); + } + else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(Ex)) { + if (const ObjCMethodDecl *MD = ME->getMethodDecl()) + T = MD->getResultType(); + } + if (Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType())) { unsigned Count = Builder.getCurrentBlockCount(); ValueManager &ValMgr = Eng.getValueManager(); diff --git a/lib/Analysis/CallInliner.cpp b/lib/Analysis/CallInliner.cpp index 43523c293d585..d18bbcc0174ac 100644 --- a/lib/Analysis/CallInliner.cpp +++ b/lib/Analysis/CallInliner.cpp @@ -11,36 +11,46 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/PathSensitive/GRExprEngine.h" -#include "clang/Analysis/PathSensitive/GRTransferFuncs.h" +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" +#include "clang/Analysis/PathSensitive/GRState.h" +#include "clang/Analysis/LocalCheckers.h" using namespace clang; namespace { - -class CallInliner : public GRTransferFuncs { - ASTContext &Ctx; +class CallInliner : public Checker { public: - CallInliner(ASTContext &ctx) : Ctx(ctx) {} + static void *getTag() { + static int x; + return &x; + } - void EvalCall(ExplodedNodeSet& Dst, GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, CallExpr* CE, SVal L, - ExplodedNode* Pred); - + virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE); + virtual void EvalEndPath(GREndPathNodeBuilder &B,void *tag,GRExprEngine &Eng); }; +} +void clang::RegisterCallInliner(GRExprEngine &Eng) { + Eng.registerCheck(new CallInliner()); } -void CallInliner::EvalCall(ExplodedNodeSet& Dst, GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, CallExpr* CE, SVal L, - ExplodedNode* Pred) { - FunctionDecl const *FD = L.getAsFunctionDecl(); +bool CallInliner::EvalCallExpr(CheckerContext &C, const CallExpr *CE) { + const GRState *state = C.getState(); + const Expr *Callee = CE->getCallee(); + SVal L = state->getSVal(Callee); + + const FunctionDecl *FD = L.getAsFunctionDecl(); if (!FD) - return; // GRExprEngine is responsible for the autotransition. + return false; + + if (!FD->isThisDeclarationADefinition()) + return false; + GRStmtNodeBuilder &Builder = C.getNodeBuilder(); // Make a new LocationContext. - StackFrameContext const *LocCtx = - Engine.getAnalysisManager().getStackFrame(FD, Pred->getLocationContext(), CE); + const StackFrameContext *LocCtx = C.getAnalysisManager().getStackFrame(FD, + C.getPredecessor()->getLocationContext(), CE, + Builder.getBlock(), Builder.getIndex()); CFGBlock const *Entry = &(LocCtx->getCFG()->getEntry()); @@ -54,22 +64,50 @@ void CallInliner::EvalCall(ExplodedNodeSet& Dst, GRExprEngine& Engine, // Construct an edge representing the starting location in the function. BlockEdge Loc(Entry, SuccB, LocCtx); - GRState const *state = Builder.GetState(Pred); - state = Engine.getStoreManager().EnterStackFrame(state, LocCtx); - + state = C.getStoreManager().EnterStackFrame(state, LocCtx); + // This is a hack. We really should not use the GRStmtNodeBuilder. bool isNew; - ExplodedNode *SuccN = Engine.getGraph().getNode(Loc, state, &isNew); - SuccN->addPredecessor(Pred, Engine.getGraph()); - - Builder.Deferred.erase(Pred); + GRExprEngine &Eng = C.getEngine(); + ExplodedNode *Pred = C.getPredecessor(); + - // This is a hack. We really should not use the GRStmtNodeBuilder. + ExplodedNode *SuccN = Eng.getGraph().getNode(Loc, state, &isNew); + SuccN->addPredecessor(Pred, Eng.getGraph()); + C.getNodeBuilder().Deferred.erase(Pred); + if (isNew) Builder.getWorkList()->Enqueue(SuccN); Builder.HasGeneratedNode = true; + + return true; } - -GRTransferFuncs *clang::CreateCallInliner(ASTContext &ctx) { - return new CallInliner(ctx); + +void CallInliner::EvalEndPath(GREndPathNodeBuilder &B, void *tag, + GRExprEngine &Eng) { + const GRState *state = B.getState(); + ExplodedNode *Pred = B.getPredecessor(); + const StackFrameContext *LocCtx = + cast<StackFrameContext>(Pred->getLocationContext()); + + const Stmt *CE = LocCtx->getCallSite(); + + // Check if this is the top level stack frame. + if (!LocCtx->getParent()) + return; + + PostStmt NodeLoc(CE, LocCtx->getParent()); + + bool isNew; + ExplodedNode *Succ = Eng.getGraph().getNode(NodeLoc, state, &isNew); + Succ->addPredecessor(Pred, Eng.getGraph()); + + // When creating the new work list unit, increment the statement index to + // point to the statement after the CallExpr. + if (isNew) + B.getWorkList().Enqueue(Succ, + *const_cast<CFGBlock*>(LocCtx->getCallSiteBlock()), + LocCtx->getIndex() + 1); + + B.HasGeneratedNode = true; } diff --git a/lib/Analysis/CheckDeadStores.cpp b/lib/Analysis/CheckDeadStores.cpp index db9016fa1e645..6e4d8998620d2 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,13 +189,22 @@ 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. if (isa<CXXConstructExpr>(E)) return; + + if (isa<CXXExprWithTemporaries>(E)) + return; + // A dead initialization is a variable that is dead after it // is initialized. We don't flag warnings for those variables // marked 'unused'. @@ -218,6 +233,7 @@ public: Report(V, DeadInit, V->getLocation(), E->getSourceRange()); } } + } } } }; diff --git a/lib/Analysis/GRCoreEngine.cpp b/lib/Analysis/GRCoreEngine.cpp index 644dd199bead1..209452a3927ac 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, @@ -213,9 +213,9 @@ void GRCoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) { CFGBlock* Blk = L.getDst(); // Check if we are entering the EXIT block. - if (Blk == &(Pred->getLocationContext()->getCFG()->getExit())) { + if (Blk == &(L.getLocationContext()->getCFG()->getExit())) { - assert (Pred->getLocationContext()->getCFG()->getExit().size() == 0 + assert (L.getLocationContext()->getCFG()->getExit().size() == 0 && "EXIT block cannot contain Stmts."); // Process the final state transition. @@ -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); @@ -447,7 +447,7 @@ GRStmtNodeBuilder::generateNodeInternal(const Stmt* S, const GRState* state, ProgramPoint::Kind K, const void *tag) { - const ProgramPoint &L = GetProgramPoint(S, K, Pred->getLocationContext(),tag); + const ProgramPoint &L = GetProgramPoint(S, K, Pred->getLocationContext(),tag); return generateNodeInternal(L, state, Pred); } diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index 51e6a547529f0..2ce8edd1cc466 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; @@ -45,6 +46,29 @@ static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) { return Ctx.Selectors.getSelector(0, &II); } + +static bool CalleeReturnsReference(const CallExpr *CE) { + const Expr *Callee = CE->getCallee(); + QualType T = Callee->getType(); + + if (const PointerType *PT = T->getAs<PointerType>()) { + const FunctionType *FT = PT->getPointeeType()->getAs<FunctionType>(); + T = FT->getResultType(); + } + else { + const BlockPointerType *BT = T->getAs<BlockPointerType>(); + T = BT->getPointeeType()->getAs<FunctionType>()->getResultType(); + } + return T->isReferenceType(); +} + +static bool ReceiverReturnsReference(const ObjCMessageExpr *ME) { + const ObjCMethodDecl *MD = ME->getMethodDecl(); + if (!MD) + return false; + return MD->getResultType()->isReferenceType(); +} + //===----------------------------------------------------------------------===// // Batch auditor. DEPRECATED. //===----------------------------------------------------------------------===// @@ -227,7 +251,7 @@ void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE, CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; CurrSet->clear(); } - + void *tag = I->first; Checker *checker = I->second; @@ -306,8 +330,9 @@ GRExprEngine::~GRExprEngine() { // Utility methods. //===----------------------------------------------------------------------===// -void GRExprEngine::setTransferFunctions(GRTransferFuncs* tf) { +void GRExprEngine::setTransferFunctionsAndCheckers(GRTransferFuncs* tf) { StateMgr.TF = tf; + StateMgr.Checkers = &Checkers; tf->RegisterChecks(*this); tf->RegisterPrinters(getStateManager().Printers); } @@ -333,43 +358,55 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) { // FIXME: It would be nice if we had a more general mechanism to add // such preconditions. Some day. - const Decl *D = InitLoc->getDecl(); - - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - // Precondition: the first argument of 'main' is an integer guaranteed - // to be > 0. - if (FD->getIdentifier()->getName() == "main" && - FD->getNumParams() > 0) { + do { + const Decl *D = InitLoc->getDecl(); + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + // Precondition: the first argument of 'main' is an integer guaranteed + // to be > 0. + const IdentifierInfo *II = FD->getIdentifier(); + if (!II || !(II->getName() == "main" && FD->getNumParams() > 0)) + break; + const ParmVarDecl *PD = FD->getParamDecl(0); QualType T = PD->getType(); - if (T->isIntegerType()) - if (const MemRegion *R = state->getRegion(PD, InitLoc)) { - SVal V = state->getSVal(loc::MemRegionVal(R)); - SVal Constraint_untested = EvalBinOp(state, BinaryOperator::GT, V, - ValMgr.makeZeroVal(T), - getContext().IntTy); - - if (DefinedOrUnknownSVal *Constraint = - dyn_cast<DefinedOrUnknownSVal>(&Constraint_untested)) { - if (const GRState *newState = state->Assume(*Constraint, true)) - state = newState; - } - } + if (!T->isIntegerType()) + break; + + const MemRegion *R = state->getRegion(PD, InitLoc); + if (!R) + break; + + SVal V = state->getSVal(loc::MemRegionVal(R)); + SVal Constraint_untested = EvalBinOp(state, BinaryOperator::GT, V, + ValMgr.makeZeroVal(T), + getContext().IntTy); + + DefinedOrUnknownSVal *Constraint = + dyn_cast<DefinedOrUnknownSVal>(&Constraint_untested); + + if (!Constraint) + break; + + if (const GRState *newState = state->Assume(*Constraint, true)) + state = newState; + + break; } - } - else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { - // Precondition: 'self' is always non-null upon entry to an Objective-C - // method. - const ImplicitParamDecl *SelfD = MD->getSelfDecl(); - const MemRegion *R = state->getRegion(SelfD, InitLoc); - SVal V = state->getSVal(loc::MemRegionVal(R)); + + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + // Precondition: 'self' is always non-null upon entry to an Objective-C + // method. + const ImplicitParamDecl *SelfD = MD->getSelfDecl(); + const MemRegion *R = state->getRegion(SelfD, InitLoc); + SVal V = state->getSVal(loc::MemRegionVal(R)); - if (const Loc *LV = dyn_cast<Loc>(&V)) { - // Assume that the pointer value in 'self' is non-null. - state = state->Assume(*LV, true); - assert(state && "'self' cannot be null"); + if (const Loc *LV = dyn_cast<Loc>(&V)) { + // Assume that the pointer value in 'self' is non-null. + state = state->Assume(*LV, true); + assert(state && "'self' cannot be null"); + } } - } + } while (0); return state; } @@ -378,17 +415,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 +450,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 +472,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 +492,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 +503,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); } } @@ -504,7 +542,6 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { case Stmt::CXXTypeidExprClass: case Stmt::CXXBoolLiteralExprClass: case Stmt::CXXNullPtrLiteralExprClass: - case Stmt::CXXThisExprClass: case Stmt::CXXThrowExprClass: case Stmt::CXXDefaultArgExprClass: case Stmt::CXXZeroInitValueExprClass: @@ -565,7 +602,8 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { break; } - if (AMgr.shouldEagerlyAssume() && (B->isRelationalOp() || B->isEqualityOp())) { + if (AMgr.shouldEagerlyAssume() && + (B->isRelationalOp() || B->isEqualityOp())) { ExplodedNodeSet Tmp; VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Tmp, false); EvalEagerlyAssume(Dst, Tmp, cast<Expr>(S)); @@ -579,7 +617,7 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { case Stmt::CallExprClass: case Stmt::CXXOperatorCallExprClass: { CallExpr* C = cast<CallExpr>(S); - VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst); + VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, false); break; } @@ -606,6 +644,10 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { break; } + case Stmt::CXXThisExprClass: + VisitCXXThisExpr(cast<CXXThisExpr>(S), Pred, Dst); + break; + case Stmt::DeclRefExprClass: VisitDeclRefExpr(cast<DeclRefExpr>(S), Pred, Dst, false); break; @@ -614,12 +656,24 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { VisitDeclStmt(cast<DeclStmt>(S), Pred, Dst); break; + case Stmt::ForStmtClass: + // This case isn't for branch processing, but for handling the + // initialization of a condition variable. + VisitCondInit(cast<ForStmt>(S)->getConditionVariable(), S, Pred, Dst); + break; + case Stmt::ImplicitCastExprClass: case Stmt::CStyleCastExprClass: { CastExpr* C = cast<CastExpr>(S); - VisitCast(C, C->getSubExpr(), Pred, Dst); + VisitCast(C, C->getSubExpr(), Pred, Dst, false); break; } + + case Stmt::IfStmtClass: + // This case isn't for branch processing, but for handling the + // initialization of a condition variable. + VisitCondInit(cast<IfStmt>(S)->getConditionVariable(), S, Pred, Dst); + break; case Stmt::InitListExprClass: VisitInitListExpr(cast<InitListExpr>(S), Pred, Dst); @@ -637,10 +691,9 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S), Pred, Dst); break; - case Stmt::ObjCMessageExprClass: { - VisitObjCMessageExpr(cast<ObjCMessageExpr>(S), Pred, Dst); + case Stmt::ObjCMessageExprClass: + VisitObjCMessageExpr(cast<ObjCMessageExpr>(S), Pred, Dst, false); break; - } case Stmt::ObjCAtThrowStmtClass: { // FIXME: This is not complete. We basically treat @throw as @@ -687,10 +740,16 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { case Stmt::StringLiteralClass: VisitLValue(cast<StringLiteral>(S), Pred, Dst); break; + + case Stmt::SwitchStmtClass: + // This case isn't for branch processing, but for handling the + // initialization of a condition variable. + VisitCondInit(cast<SwitchStmt>(S)->getConditionVariable(), S, Pred, Dst); + break; case Stmt::UnaryOperatorClass: { UnaryOperator *U = cast<UnaryOperator>(S); - if (AMgr.shouldEagerlyAssume() && (U->getOpcode() == UnaryOperator::LNot)) { + if (AMgr.shouldEagerlyAssume()&&(U->getOpcode() == UnaryOperator::LNot)) { ExplodedNodeSet Tmp; VisitUnaryOperator(U, Pred, Tmp, false); EvalEagerlyAssume(Dst, Tmp, U); @@ -699,48 +758,92 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { VisitUnaryOperator(U, Pred, Dst, false); break; } + + case Stmt::WhileStmtClass: + // This case isn't for branch processing, but for handling the + // initialization of a condition variable. + VisitCondInit(cast<WhileStmt>(S)->getConditionVariable(), S, Pred, Dst); + break; } } void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, ExplodedNodeSet& Dst) { + + PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), + Ex->getLocStart(), + "Error evaluating statement"); + Ex = Ex->IgnoreParens(); - if (Ex != CurrentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(Ex)) { + if (Ex != CurrentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(Ex)){ Dst.Add(Pred); return; } switch (Ex->getStmtClass()) { + // C++ stuff we don't support yet. + case Stmt::CXXExprWithTemporariesClass: + case Stmt::CXXMemberCallExprClass: + case Stmt::CXXZeroInitValueExprClass: { + SaveAndRestore<bool> OldSink(Builder->BuildSinks); + Builder->BuildSinks = true; + MakeNode(Dst, Ex, Pred, GetState(Pred)); + break; + } case Stmt::ArraySubscriptExprClass: VisitArraySubscriptExpr(cast<ArraySubscriptExpr>(Ex), Pred, Dst, true); return; + case Stmt::BinaryOperatorClass: + case Stmt::CompoundAssignOperatorClass: + VisitBinaryOperator(cast<BinaryOperator>(Ex), Pred, Dst, true); + return; + case Stmt::BlockDeclRefExprClass: VisitBlockDeclRefExpr(cast<BlockDeclRefExpr>(Ex), Pred, Dst, true); return; + + case Stmt::CallExprClass: + case Stmt::CXXOperatorCallExprClass: { + CallExpr *C = cast<CallExpr>(Ex); + assert(CalleeReturnsReference(C)); + VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, true); + break; + } + + case Stmt::CompoundLiteralExprClass: + VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(Ex), Pred, Dst, true); + return; case Stmt::DeclRefExprClass: VisitDeclRefExpr(cast<DeclRefExpr>(Ex), Pred, Dst, true); return; - - case Stmt::ObjCIvarRefExprClass: - VisitObjCIvarRefExpr(cast<ObjCIvarRefExpr>(Ex), Pred, Dst, true); - return; - - case Stmt::UnaryOperatorClass: - VisitUnaryOperator(cast<UnaryOperator>(Ex), Pred, Dst, true); - return; - + + case Stmt::ImplicitCastExprClass: + case Stmt::CStyleCastExprClass: { + CastExpr *C = cast<CastExpr>(Ex); + QualType T = Ex->getType(); + VisitCast(C, C->getSubExpr(), Pred, Dst, true); + break; + } + case Stmt::MemberExprClass: VisitMemberExpr(cast<MemberExpr>(Ex), Pred, Dst, true); return; - case Stmt::CompoundLiteralExprClass: - VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(Ex), Pred, Dst, true); + case Stmt::ObjCIvarRefExprClass: + VisitObjCIvarRefExpr(cast<ObjCIvarRefExpr>(Ex), Pred, Dst, true); + return; + + case Stmt::ObjCMessageExprClass: { + ObjCMessageExpr *ME = cast<ObjCMessageExpr>(Ex); + assert(ReceiverReturnsReference(ME)); + VisitObjCMessageExpr(ME, Pred, Dst, true); return; + } case Stmt::ObjCPropertyRefExprClass: case Stmt::ObjCImplicitSetterGetterRefExprClass: @@ -765,11 +868,10 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, return; } - case Stmt::BinaryOperatorClass: - case Stmt::CompoundAssignOperatorClass: - VisitBinaryOperator(cast<BinaryOperator>(Ex), Pred, Dst, true); + case Stmt::UnaryOperatorClass: + VisitUnaryOperator(cast<UnaryOperator>(Ex), Pred, Dst, true); return; - + default: // Arbitrary subexpressions can return aggregate temporaries that // can be used in a lvalue context. We need to enhance our support @@ -1023,7 +1125,8 @@ void GRExprEngine::ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder) { void GRExprEngine::VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, ExplodedNode* Pred, ExplodedNodeSet& Dst) { - assert (Ex == CurrentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(Ex)); + assert(Ex == CurrentStmt && + Pred->getLocationContext()->getCFG()->isBlkExpr(Ex)); const GRState* state = GetState(Pred); SVal X = state->getSVal(Ex); @@ -1147,7 +1250,7 @@ void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred, assert(B->getOpcode() == BinaryOperator::LAnd || B->getOpcode() == BinaryOperator::LOr); - assert(B == CurrentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(B)); + assert(B==CurrentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(B)); const GRState* state = GetState(Pred); SVal X = state->getSVal(B); @@ -1232,13 +1335,23 @@ void GRExprEngine::VisitCommonDeclRefExpr(Expr *Ex, const NamedDecl *D, SVal V = state->getLValue(VD, Pred->getLocationContext()); - if (asLValue) + 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 +1528,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); @@ -1489,94 +1633,111 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S, // Transfer function: Function calls. //===----------------------------------------------------------------------===// +namespace { +class CallExprWLItem { +public: + CallExpr::arg_iterator I; + ExplodedNode *N; + + CallExprWLItem(const CallExpr::arg_iterator &i, ExplodedNode *n) + : I(i), N(n) {} +}; +} // end anonymous namespace + void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, CallExpr::arg_iterator AI, CallExpr::arg_iterator AE, - ExplodedNodeSet& Dst) { + ExplodedNodeSet& Dst, bool asLValue) { + // Determine the type of function we're calling (if available). const FunctionProtoType *Proto = NULL; QualType FnType = CE->getCallee()->IgnoreParens()->getType(); if (const PointerType *FnTypePtr = FnType->getAs<PointerType>()) Proto = FnTypePtr->getPointeeType()->getAs<FunctionProtoType>(); - VisitCallRec(CE, Pred, AI, AE, Dst, Proto, /*ParamIdx=*/0); -} - -void GRExprEngine::VisitCallRec(CallExpr* CE, ExplodedNode* Pred, - CallExpr::arg_iterator AI, - CallExpr::arg_iterator AE, - ExplodedNodeSet& Dst, - const FunctionProtoType *Proto, - unsigned ParamIdx) { + // Create a worklist to process the arguments. + llvm::SmallVector<CallExprWLItem, 20> WorkList; + WorkList.reserve(AE - AI); + WorkList.push_back(CallExprWLItem(AI, Pred)); + + ExplodedNodeSet ArgsEvaluated; - // Process the arguments. - if (AI != AE) { - // If the call argument is being bound to a reference parameter, - // visit it as an lvalue, not an rvalue. + while (!WorkList.empty()) { + CallExprWLItem Item = WorkList.back(); + WorkList.pop_back(); + + if (Item.I == AE) { + ArgsEvaluated.insert(Item.N); + continue; + } + + // Evaluate the argument. + ExplodedNodeSet Tmp; + const unsigned ParamIdx = Item.I - AI; + bool VisitAsLvalue = false; if (Proto && ParamIdx < Proto->getNumArgs()) VisitAsLvalue = Proto->getArgType(ParamIdx)->isReferenceType(); - - ExplodedNodeSet DstTmp; + if (VisitAsLvalue) - VisitLValue(*AI, Pred, DstTmp); + VisitLValue(*Item.I, Item.N, Tmp); else - Visit(*AI, Pred, DstTmp); - ++AI; + Visit(*Item.I, Item.N, Tmp); + + // Enqueue evaluating the next argument on the worklist. + ++(Item.I); - for (ExplodedNodeSet::iterator DI=DstTmp.begin(), DE=DstTmp.end(); DI != DE; - ++DI) - VisitCallRec(CE, *DI, AI, AE, Dst, Proto, ParamIdx + 1); - - return; + for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) + WorkList.push_back(CallExprWLItem(Item.I, *NI)); } - // If we reach here we have processed all of the arguments. Evaluate - // the callee expression. + // Now process the call itself. ExplodedNodeSet DstTmp; Expr* Callee = CE->getCallee()->IgnoreParens(); - - { // Enter new scope to make the lifetime of 'DstTmp2' bounded. + + for (ExplodedNodeSet::iterator NI=ArgsEvaluated.begin(), + NE=ArgsEvaluated.end(); NI != NE; ++NI) { + // Evaluate the callee. ExplodedNodeSet DstTmp2; - Visit(Callee, Pred, DstTmp2); - + Visit(Callee, *NI, DstTmp2); // Perform the previsit of the CallExpr, storing the results in DstTmp. CheckerVisit(CE, DstTmp, DstTmp2, true); } - - // Finally, evaluate the function call. + + // Finally, evaluate the function call. We try each of the checkers + // to see if the can evaluate the function call. ExplodedNodeSet DstTmp3; + for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); DI != DE; ++DI) { - + const GRState* state = GetState(*DI); SVal L = state->getSVal(Callee); - + // FIXME: Add support for symbolic function calls (calls involving // function pointer values that are symbolic). SaveAndRestore<bool> OldSink(Builder->BuildSinks); ExplodedNodeSet DstChecker; - + // If the callee is processed by a checker, skip the rest logic. if (CheckerEvalCall(CE, DstChecker, *DI)) DstTmp3.insert(DstChecker); else { for (ExplodedNodeSet::iterator DI_Checker = DstChecker.begin(), - DE_Checker = DstChecker.end(); - DI_Checker != DE_Checker; ++DI_Checker) { - - // Dispatch to the plug-in transfer function. + DE_Checker = DstChecker.end(); + DI_Checker != DE_Checker; ++DI_Checker) { + + // Dispatch to the plug-in transfer function. unsigned OldSize = DstTmp3.size(); SaveOr OldHasGen(Builder->HasGeneratedNode); Pred = *DI_Checker; - + // Dispatch to transfer function logic to handle the call itself. // FIXME: Allow us to chain together transfer functions. - assert(Builder && "GRStmtNodeBuilder must be defined."); - + assert(Builder && "GRStmtNodeBuilder must be defined."); getTF().EvalCall(DstTmp3, *this, *Builder, CE, L, Pred); - + // Handle the case where no nodes where generated. Auto-generate that // contains the updated state if we aren't generating sinks. if (!Builder->BuildSinks && DstTmp3.size() == OldSize && @@ -1585,9 +1746,31 @@ void GRExprEngine::VisitCallRec(CallExpr* CE, ExplodedNode* Pred, } } } - - // Perform the post-condition check of the CallExpr. - CheckerVisit(CE, Dst, DstTmp3, false); + + // Finally, perform the post-condition check of the CallExpr and store + // the created nodes in 'Dst'. + + if (!(!asLValue && CalleeReturnsReference(CE))) { + CheckerVisit(CE, Dst, DstTmp3, false); + return; + } + + // Handle the case where the called function returns a reference but + // we expect an rvalue. For such cases, convert the reference to + // an rvalue. + // FIXME: This conversion doesn't actually happen unless the result + // of CallExpr is consumed by another expression. + ExplodedNodeSet DstTmp4; + CheckerVisit(CE, DstTmp4, DstTmp3, false); + QualType LoadTy = CE->getType(); + + static int *ConvertToRvalueTag = 0; + for (ExplodedNodeSet::iterator NI = DstTmp4.begin(), NE = DstTmp4.end(); + NI!=NE; ++NI) { + const GRState *state = GetState(*NI); + EvalLoad(Dst, CE, *NI, state, state->getSVal(CE), + &ConvertToRvalueTag, LoadTy); + } } //===----------------------------------------------------------------------===// @@ -1764,16 +1947,18 @@ void GRExprEngine::VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S, //===----------------------------------------------------------------------===// void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred, - ExplodedNodeSet& Dst){ + ExplodedNodeSet& Dst, bool asLValue){ VisitObjCMessageExprArgHelper(ME, ME->arg_begin(), ME->arg_end(), - Pred, Dst); + Pred, Dst, asLValue); } void GRExprEngine::VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME, - ObjCMessageExpr::arg_iterator AI, - ObjCMessageExpr::arg_iterator AE, - ExplodedNode* Pred, ExplodedNodeSet& Dst) { + ObjCMessageExpr::arg_iterator AI, + ObjCMessageExpr::arg_iterator AE, + ExplodedNode* Pred, + ExplodedNodeSet& Dst, + bool asLValue) { if (AI == AE) { // Process the receiver. @@ -1784,12 +1969,12 @@ void GRExprEngine::VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME, for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE; ++NI) - VisitObjCMessageExprDispatchHelper(ME, *NI, Dst); + VisitObjCMessageExprDispatchHelper(ME, *NI, Dst, asLValue); return; } - VisitObjCMessageExprDispatchHelper(ME, Pred, Dst); + VisitObjCMessageExprDispatchHelper(ME, Pred, Dst, asLValue); return; } @@ -1799,12 +1984,13 @@ void GRExprEngine::VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME, ++AI; for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end();NI != NE;++NI) - VisitObjCMessageExprArgHelper(ME, AI, AE, *NI, Dst); + VisitObjCMessageExprArgHelper(ME, AI, AE, *NI, Dst, asLValue); } void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, ExplodedNode* Pred, - ExplodedNodeSet& Dst) { + ExplodedNodeSet& Dst, + bool asLValue) { // Handle previsits checks. ExplodedNodeSet Src, DstTmp; @@ -1812,12 +1998,17 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, CheckerVisit(ME, DstTmp, Src, true); - unsigned size = Dst.size(); + ExplodedNodeSet PostVisitSrc; for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); DI!=DE; ++DI) { + Pred = *DI; bool RaisesException = false; + + unsigned OldSize = PostVisitSrc.size(); + SaveAndRestore<bool> OldSink(Builder->BuildSinks); + SaveOr OldHasGen(Builder->HasGeneratedNode); if (const Expr *Receiver = ME->getReceiver()) { const GRState *state = Pred->getState(); @@ -1832,8 +2023,8 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, // There are three cases: can be nil or non-nil, must be nil, must be // non-nil. We handle must be nil, and merge the rest two into non-nil. if (nilState && !notNilState) { - CheckerEvalNilReceiver(ME, Dst, nilState, Pred); - return; + CheckerEvalNilReceiver(ME, PostVisitSrc, nilState, Pred); + continue; } assert(notNilState); @@ -1844,39 +2035,29 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, // Check if we raise an exception. For now treat these as sinks. // Eventually we will want to handle exceptions properly. - SaveAndRestore<bool> OldSink(Builder->BuildSinks); if (RaisesException) Builder->BuildSinks = true; // Dispatch to plug-in transfer function. - SaveOr OldHasGen(Builder->HasGeneratedNode); - EvalObjCMessageExpr(Dst, ME, Pred, notNilState); + EvalObjCMessageExpr(PostVisitSrc, ME, Pred, notNilState); } else { - IdentifierInfo* ClsName = ME->getClassName(); Selector S = ME->getSelector(); // Check for special instance methods. - if (!NSExceptionII) { ASTContext& Ctx = getContext(); - NSExceptionII = &Ctx.Idents.get("NSException"); } if (ClsName == NSExceptionII) { - enum { NUM_RAISE_SELECTORS = 2 }; // Lazily create a cache of the selectors. - if (!NSExceptionInstanceRaiseSelectors) { - ASTContext& Ctx = getContext(); - NSExceptionInstanceRaiseSelectors = new Selector[NUM_RAISE_SELECTORS]; - llvm::SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II; unsigned idx = 0; @@ -1894,26 +2075,51 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) if (S == NSExceptionInstanceRaiseSelectors[i]) { - RaisesException = true; break; + RaisesException = true; + break; } } // Check if we raise an exception. For now treat these as sinks. // Eventually we will want to handle exceptions properly. - SaveAndRestore<bool> OldSink(Builder->BuildSinks); if (RaisesException) Builder->BuildSinks = true; // Dispatch to plug-in transfer function. - SaveOr OldHasGen(Builder->HasGeneratedNode); - EvalObjCMessageExpr(Dst, ME, Pred, Builder->GetState(Pred)); + EvalObjCMessageExpr(PostVisitSrc, ME, Pred, Builder->GetState(Pred)); } + + // Handle the case where no nodes where generated. Auto-generate that + // contains the updated state if we aren't generating sinks. + if (!Builder->BuildSinks && PostVisitSrc.size() == OldSize && + !Builder->HasGeneratedNode) + MakeNode(PostVisitSrc, ME, Pred, GetState(Pred)); } - // Handle the case where no nodes where generated. Auto-generate that - // contains the updated state if we aren't generating sinks. - if (!Builder->BuildSinks && Dst.size() == size && !Builder->HasGeneratedNode) - MakeNode(Dst, ME, Pred, GetState(Pred)); + // Finally, perform the post-condition check of the ObjCMessageExpr and store + // the created nodes in 'Dst'. + if (!(!asLValue && ReceiverReturnsReference(ME))) { + CheckerVisit(ME, Dst, PostVisitSrc, false); + return; + } + + // Handle the case where the message expression returns a reference but + // we expect an rvalue. For such cases, convert the reference to + // an rvalue. + // FIXME: This conversion doesn't actually happen unless the result + // of ObjCMessageExpr is consumed by another expression. + ExplodedNodeSet DstRValueConvert; + CheckerVisit(ME, DstRValueConvert, PostVisitSrc, false); + QualType LoadTy = ME->getType(); + + static int *ConvertToRvalueTag = 0; + for (ExplodedNodeSet::iterator NI = DstRValueConvert.begin(), + NE = DstRValueConvert.end(); + NI!=NE; ++NI) { + const GRState *state = GetState(*NI); + EvalLoad(Dst, ME, *NI, state, state->getSVal(ME), + &ConvertToRvalueTag, LoadTy); + } } //===----------------------------------------------------------------------===// @@ -1921,7 +2127,7 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, //===----------------------------------------------------------------------===// void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, - ExplodedNodeSet& Dst){ + ExplodedNodeSet& Dst, bool asLValue){ ExplodedNodeSet S1; QualType T = CastE->getType(); QualType ExTy = Ex->getType(); @@ -1929,7 +2135,8 @@ void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE)) T = ExCast->getTypeAsWritten(); - if (ExTy->isArrayType() || ExTy->isFunctionType() || T->isReferenceType()) + if (ExTy->isArrayType() || ExTy->isFunctionType() || T->isReferenceType() || + asLValue) VisitLValue(Ex, Pred, S1); else Visit(Ex, Pred, S1); @@ -1939,10 +2146,19 @@ void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, // Check for casting to "void". if (T->isVoidType()) { + assert(!asLValue); for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) Dst.Add(*I); return; } + + // If we are evaluating the cast in an lvalue context, we implicitly want + // the cast to evaluate to a location. + if (asLValue) { + ASTContext &Ctx = getContext(); + T = Ctx.getPointerType(Ctx.getCanonicalType(T)); + ExTy = Ctx.getPointerType(Ctx.getCanonicalType(ExTy)); + } for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) { ExplodedNode* N = *I; @@ -1992,8 +2208,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); @@ -2009,7 +2229,6 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, if (InitEx) { SVal InitVal = state->getSVal(InitEx); - QualType T = VD->getType(); // Recover some path-sensitivity if a scalar value evaluated to // UnknownVal. @@ -2020,7 +2239,7 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, } EvalBind(Dst, DS, DS, *I, state, - loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true); + loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true); } else { state = state->bindDeclWithNoInit(state->getRegion(VD, LC)); @@ -2029,6 +2248,33 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, } } +void GRExprEngine::VisitCondInit(VarDecl *VD, Stmt *S, + ExplodedNode *Pred, ExplodedNodeSet& Dst) { + + Expr* InitEx = VD->getInit(); + ExplodedNodeSet Tmp; + Visit(InitEx, Pred, Tmp); + + for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { + ExplodedNode *N = *I; + const GRState *state = GetState(N); + + const LocationContext *LC = N->getLocationContext(); + SVal InitVal = state->getSVal(InitEx); + + // Recover some path-sensitivity if a scalar value evaluated to + // UnknownVal. + if (InitVal.isUnknown() || + !getConstraintManager().canReasonAbout(InitVal)) { + InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx, + Builder->getCurrentBlockCount()); + } + + EvalBind(Dst, S, S, N, state, + loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true); + } +} + namespace { // This class is used by VisitInitListExpr as an item in a worklist // for processing the values contained in an InitListExpr. @@ -2082,7 +2328,7 @@ void GRExprEngine::VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred, InitListExpr::reverse_iterator NewItr = X.Itr + 1; - for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) { + for (ExplodedNodeSet::iterator NI=Tmp.begin(),NE=Tmp.end();NI!=NE;++NI) { // Get the last initializer value. state = GetState(*NI); SVal InitV = state->getSVal(cast<Expr>(*X.Itr)); @@ -2114,7 +2360,7 @@ void GRExprEngine::VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred, ExplodedNodeSet Tmp; Expr* Init = E->getInit(0); Visit(Init, Pred, Tmp); - for (ExplodedNodeSet::iterator I = Tmp.begin(), EI = Tmp.end(); I != EI; ++I) { + for (ExplodedNodeSet::iterator I=Tmp.begin(), EI=Tmp.end(); I != EI; ++I) { state = GetState(*I); MakeNode(Dst, E, *I, state->BindExpr(E, state->getSVal(Init))); } @@ -2382,7 +2628,7 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, ExplodedNodeSet Tmp2; EvalLoad(Tmp2, Ex, *I, state, V1); - for (ExplodedNodeSet::iterator I2 = Tmp2.begin(), E2 = Tmp2.end(); I2!=E2; ++I2) { + for (ExplodedNodeSet::iterator I2=Tmp2.begin(), E2=Tmp2.end();I2!=E2;++I2) { state = GetState(*I2); SVal V2_untested = state->getSVal(Ex); @@ -2445,14 +2691,23 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, } } -void GRExprEngine::VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred, ExplodedNodeSet& Dst) { + +void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred, + ExplodedNodeSet & Dst) { + // Get the this object region from StoreManager. + Loc V = getStoreManager().getThisObject(TE->getType()->getPointeeType()); + MakeNode(Dst, TE, Pred, GetState(Pred)->BindExpr(TE, V)); +} + +void GRExprEngine::VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred, + ExplodedNodeSet& Dst) { VisitAsmStmtHelperOutputs(A, A->begin_outputs(), A->end_outputs(), Pred, Dst); } void GRExprEngine::VisitAsmStmtHelperOutputs(AsmStmt* A, AsmStmt::outputs_iterator I, AsmStmt::outputs_iterator E, - ExplodedNode* Pred, ExplodedNodeSet& Dst) { + ExplodedNode* Pred, ExplodedNodeSet& Dst) { if (I == E) { VisitAsmStmtHelperInputs(A, A->begin_inputs(), A->end_inputs(), Pred, Dst); return; @@ -2463,14 +2718,15 @@ void GRExprEngine::VisitAsmStmtHelperOutputs(AsmStmt* A, ++I; - for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE; ++NI) + for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end();NI != NE;++NI) VisitAsmStmtHelperOutputs(A, I, E, *NI, Dst); } void GRExprEngine::VisitAsmStmtHelperInputs(AsmStmt* A, AsmStmt::inputs_iterator I, AsmStmt::inputs_iterator E, - ExplodedNode* Pred, ExplodedNodeSet& Dst) { + ExplodedNode* Pred, + ExplodedNodeSet& Dst) { if (I == E) { // We have processed both the inputs and the outputs. All of the outputs @@ -2598,7 +2854,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, // Simulate the effects of a "store": bind the value of the RHS // to the L-Value represented by the LHS. - EvalStore(Tmp3, B, LHS, *I2, state->BindExpr(B, ExprVal), LeftV, RightV); + EvalStore(Tmp3, B, LHS, *I2, state->BindExpr(B, ExprVal), LeftV,RightV); continue; } diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp index 84e268f3fdaa3..0b2620e609c2d 100644 --- a/lib/Analysis/LiveVariables.cpp +++ b/lib/Analysis/LiveVariables.cpp @@ -112,6 +112,11 @@ public: void VisitUnaryOperator(UnaryOperator* U); void Visit(Stmt *S); void VisitTerminator(CFGBlock* B); + + /// VisitConditionVariableInit - Handle the initialization of condition + /// variables at branches. Valid statements include IfStmt, ForStmt, + /// WhileStmt, and SwitchStmt. + void VisitConditionVariableInit(Stmt *S); void SetTopValue(LiveVariables::ValTy& V) { V = AD.AlwaysLive; @@ -126,7 +131,9 @@ void TransferFuncs::Visit(Stmt *S) { if (AD.Observer) AD.Observer->ObserveStmt(S,AD,LiveState); - if (getCFG().isBlkExpr(S)) LiveState(S,AD) = Dead; + if (getCFG().isBlkExpr(S)) + LiveState(S, AD) = Dead; + StmtVisitor<TransferFuncs,void>::Visit(S); } else if (!getCFG().isBlkExpr(S)) { @@ -142,6 +149,11 @@ void TransferFuncs::Visit(Stmt *S) { LiveState(S,AD) = Alive; } } + +void TransferFuncs::VisitConditionVariableInit(Stmt *S) { + assert(!getCFG().isBlkExpr(S)); + CFGRecStmtVisitor<TransferFuncs>::VisitConditionVariableInit(S); +} void TransferFuncs::VisitTerminator(CFGBlock* B) { @@ -289,17 +301,8 @@ void TransferFuncs::VisitDeclStmt(DeclStmt* DS) { //===----------------------------------------------------------------------===// namespace { - -struct Merge { - typedef StmtDeclBitVector_Types::ValTy ValTy; - - void operator()(ValTy& Dst, const ValTy& Src) { - Dst.OrDeclBits(Src); - Dst.OrBlkExprBits(Src); - } -}; - -typedef DataflowSolver<LiveVariables, TransferFuncs, Merge> Solver; + typedef StmtDeclBitVector_Types::Union Merge; + typedef DataflowSolver<LiveVariables, TransferFuncs, Merge> Solver; } // end anonymous namespace //===----------------------------------------------------------------------===// diff --git a/lib/Analysis/MallocChecker.cpp b/lib/Analysis/MallocChecker.cpp index 2ed070a170cd9..fab73ee7b104e 100644 --- a/lib/Analysis/MallocChecker.cpp +++ b/lib/Analysis/MallocChecker.cpp @@ -23,13 +23,13 @@ using namespace clang; namespace { class RefState { - enum Kind { Allocated, Released, Escaped } K; + enum Kind { AllocateUnchecked, AllocateFailed, Released, Escaped } K; const Stmt *S; public: RefState(Kind k, const Stmt *s) : K(k), S(s) {} - bool isAllocated() const { return K == Allocated; } + bool isAllocated() const { return K == AllocateUnchecked; } bool isReleased() const { return K == Released; } bool isEscaped() const { return K == Escaped; } @@ -37,7 +37,12 @@ public: return K == X.K && S == X.S; } - static RefState getAllocated(const Stmt *s) { return RefState(Allocated, s); } + static RefState getAllocateUnchecked(const Stmt *s) { + return RefState(AllocateUnchecked, s); + } + static RefState getAllocateFailed() { + return RefState(AllocateFailed, 0); + } static RefState getReleased(const Stmt *s) { return RefState(Released, s); } static RefState getEscaped(const Stmt *s) { return RefState(Escaped, s); } @@ -62,6 +67,8 @@ public: void EvalDeadSymbols(CheckerContext &C,const Stmt *S,SymbolReaper &SymReaper); void EvalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng); void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S); + const GRState *EvalAssume(const GRState *state, SVal Cond, bool Assumption); + private: void MallocMem(CheckerContext &C, const CallExpr *CE); const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE, @@ -74,6 +81,8 @@ private: }; } // end anonymous namespace +typedef llvm::ImmutableMap<SymbolRef, RefState> RegionStateTy; + namespace clang { template <> struct GRStateTrait<RegionState> @@ -144,7 +153,7 @@ const GRState *MallocChecker::MallocMemAux(CheckerContext &C, SymbolRef Sym = RetVal.getAsLocSymbol(); assert(Sym); // Set the symbol's state to Allocated. - return state->set<RegionState>(Sym, RefState::getAllocated(CE)); + return state->set<RegionState>(Sym, RefState::getAllocateUnchecked(CE)); } void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) { @@ -298,3 +307,18 @@ void MallocChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) { C.addTransition(state); } + +const GRState *MallocChecker::EvalAssume(const GRState *state, SVal Cond, + bool Assumption) { + // If a symblic region is assumed to NULL, set its state to AllocateFailed. + // FIXME: should also check symbols assumed to non-null. + + RegionStateTy RS = state->get<RegionState>(); + + for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) { + if (state->getSymVal(I.getKey())) + state = state->set<RegionState>(I.getKey(),RefState::getAllocateFailed()); + } + + return state; +} diff --git a/lib/Analysis/MemRegion.cpp b/lib/Analysis/MemRegion.cpp index bc3a5b704552c..74fe3bf5ee5c1 100644 --- a/lib/Analysis/MemRegion.cpp +++ b/lib/Analysis/MemRegion.cpp @@ -291,6 +291,17 @@ void BlockDataRegion::Profile(llvm::FoldingSetNodeID& ID) const { BlockDataRegion::ProfileRegion(ID, BC, LC, getSuperRegion()); } +void CXXObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID, + QualType T, + const MemRegion *sReg) { + ID.AddPointer(T.getTypePtr()); + ID.AddPointer(sReg); +} + +void CXXObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const { + ProfileRegion(ID, T, getSuperRegion()); +} + //===----------------------------------------------------------------------===// // Region pretty-printing. //===----------------------------------------------------------------------===// @@ -552,10 +563,9 @@ MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl* d, return getSubRegion<ObjCIvarRegion>(d, superRegion); } -const ObjCObjectRegion* -MemRegionManager::getObjCObjectRegion(const ObjCInterfaceDecl* d, - const MemRegion* superRegion) { - return getSubRegion<ObjCObjectRegion>(d, superRegion); +const CXXObjectRegion * +MemRegionManager::getCXXObjectRegion(QualType T) { + return getSubRegion<CXXObjectRegion>(T, getUnknownRegion()); } const AllocaRegion* diff --git a/lib/Analysis/NoReturnFunctionChecker.cpp b/lib/Analysis/NoReturnFunctionChecker.cpp index 6806273d4b4b9..5cfd9acd5f565 100644 --- a/lib/Analysis/NoReturnFunctionChecker.cpp +++ b/lib/Analysis/NoReturnFunctionChecker.cpp @@ -45,13 +45,12 @@ bool NoReturnFunctionChecker::EvalCallExpr(CheckerContext &C, if (FD->getAttr<NoReturnAttr>() || FD->getAttr<AnalyzerNoReturnAttr>()) BuildSinks = true; - else { + else if (const IdentifierInfo *II = FD->getIdentifier()) { // HACK: Some functions are not marked noreturn, and don't return. // Here are a few hardwired ones. If this takes too long, we can // potentially cache these results. - using llvm::StringRef; BuildSinks - = llvm::StringSwitch<bool>(StringRef(FD->getIdentifier()->getName())) + = llvm::StringSwitch<bool>(llvm::StringRef(II->getName())) .Case("exit", true) .Case("panic", true) .Case("error", true) diff --git a/lib/Analysis/OSAtomicChecker.cpp b/lib/Analysis/OSAtomicChecker.cpp index 5a893458830c5..cf16796b1b146 100644 --- a/lib/Analysis/OSAtomicChecker.cpp +++ b/lib/Analysis/OSAtomicChecker.cpp @@ -44,11 +44,15 @@ bool OSAtomicChecker::EvalCallExpr(CheckerContext &C,const CallExpr *CE) { if (!FD) return false; - const char *FName = FD->getNameAsCString(); + const IdentifierInfo *II = FD->getIdentifier(); + if (!II) + return false; + + llvm::StringRef FName(II->getName()); // Check for compare and swap. - if (strncmp(FName, "OSAtomicCompareAndSwap", 22) == 0 || - strncmp(FName, "objc_atomicCompareAndSwap", 25) == 0) + if (FName.startswith("OSAtomicCompareAndSwap") || + FName.startswith("objc_atomicCompareAndSwap")) return EvalOSAtomicCompareAndSwap(C, CE); // FIXME: Other atomics. diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp index b5eeb1ea11703..3bc9dccda6bfb 100644 --- a/lib/Analysis/RegionStore.cpp +++ b/lib/Analysis/RegionStore.cpp @@ -349,6 +349,7 @@ public: SVal RetrieveArray(const GRState *St, const TypedRegion* R); + /// Get the state and region whose binding this region R corresponds to. std::pair<const GRState*, const MemRegion*> GetLazyBinding(RegionBindings B, const MemRegion *R); @@ -539,8 +540,7 @@ const GRState *RegionStoreManager::InvalidateRegions(const GRState *state, } // Handle the region itself. - if (isa<AllocaRegion>(R) || isa<SymbolicRegion>(R) || - isa<ObjCObjectRegion>(R)) { + if (isa<AllocaRegion>(R) || isa<SymbolicRegion>(R)) { // Invalidate the region by setting its default value to // conjured symbol. The type of the symbol is irrelavant. DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, Ctx.IntTy, @@ -744,8 +744,8 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state, case MemRegion::ElementRegionKind: case MemRegion::FieldRegionKind: case MemRegion::ObjCIvarRegionKind: - case MemRegion::ObjCObjectRegionKind: case MemRegion::SymbolicRegionKind: + case MemRegion::CXXObjectRegionKind: return UnknownVal(); case MemRegion::StringRegionKind: { @@ -867,8 +867,8 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state, // Fall-through. case MemRegion::CompoundLiteralRegionKind: case MemRegion::FieldRegionKind: - case MemRegion::ObjCObjectRegionKind: case MemRegion::ObjCIvarRegionKind: + case MemRegion::CXXObjectRegionKind: return UnknownVal(); case MemRegion::FunctionTextRegionKind: @@ -987,12 +987,12 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) { assert(!isa<UnknownVal>(L) && "location unknown"); assert(!isa<UndefinedVal>(L) && "location undefined"); - + // FIXME: Is this even possible? Shouldn't this be treated as a null // dereference at a higher level? if (isa<loc::ConcreteInt>(L)) return SValuator::CastResult(state, UndefinedVal()); - + const MemRegion *MR = cast<loc::MemRegionVal>(L).getRegion(); // FIXME: return symbolic value for these cases. @@ -1090,8 +1090,7 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) { } // All other values are symbolic. - return SValuator::CastResult(state, - ValMgr.getRegionValueSymbolValOrUnknown(R, RTy)); + return SValuator::CastResult(state, ValMgr.getRegionValueSymbolVal(R, RTy)); } std::pair<const GRState*, const MemRegion*> @@ -1256,7 +1255,7 @@ SVal RegionStoreManager::RetrieveFieldOrElementCommon(const GRState *state, } // All other values are symbolic. - return ValMgr.getRegionValueSymbolValOrUnknown(R, Ty); + return ValMgr.getRegionValueSymbolVal(R, Ty); } SVal RegionStoreManager::RetrieveObjCIvar(const GRState* state, @@ -1296,7 +1295,7 @@ SVal RegionStoreManager::RetrieveVar(const GRState *state, if (R->hasGlobalsOrParametersStorage() || isa<UnknownSpaceRegion>(R->getMemorySpace())) - return ValMgr.getRegionValueSymbolValOrUnknown(R, VD->getType()); + return ValMgr.getRegionValueSymbolVal(R, VD->getType()); return UndefinedVal(); } @@ -1307,7 +1306,7 @@ SVal RegionStoreManager::RetrieveLazySymbol(const GRState *state, QualType valTy = R->getValueType(getContext()); // All other values are symbolic. - return ValMgr.getRegionValueSymbolValOrUnknown(R, valTy); + return ValMgr.getRegionValueSymbolVal(R, valTy); } SVal RegionStoreManager::RetrieveStruct(const GRState *state, @@ -1425,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/lib/Analysis/SValuator.cpp b/lib/Analysis/SValuator.cpp index ac727b0ac696c..49bc0c4c59885 100644 --- a/lib/Analysis/SValuator.cpp +++ b/lib/Analysis/SValuator.cpp @@ -72,10 +72,14 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state, // Check for casts from integers to pointers. if (Loc::IsLocType(castTy) && originalTy->isIntegerType()) { if (nonloc::LocAsInteger *LV = dyn_cast<nonloc::LocAsInteger>(&val)) { - // Just unpackage the lval and return it. + if (const MemRegion *R = LV->getLoc().getAsRegion()) { + StoreManager &storeMgr = ValMgr.getStateManager().getStoreManager(); + R = storeMgr.CastRegion(R, castTy); + return R ? CastResult(state, loc::MemRegionVal(R)) + : CastResult(state, UnknownVal()); + } return CastResult(state, LV->getLoc()); } - goto DispatchCast; } @@ -136,15 +140,12 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state, // different type. If the MemRegion* returned is NULL, this expression // evaluates to UnknownVal. R = storeMgr.CastRegion(R, castTy); - - if (R) - return CastResult(state, loc::MemRegionVal(R)); - - return CastResult(state, UnknownVal()); + return R ? CastResult(state, loc::MemRegionVal(R)) + : CastResult(state, UnknownVal()); } - // All other cases. DispatchCast: + // All other cases. return CastResult(state, isa<Loc>(val) ? EvalCastL(cast<Loc>(val), castTy) : EvalCastNL(cast<NonLoc>(val), castTy)); diff --git a/lib/Analysis/SimpleConstraintManager.cpp b/lib/Analysis/SimpleConstraintManager.cpp index 015db76080dfb..23c3b41758359 100644 --- a/lib/Analysis/SimpleConstraintManager.cpp +++ b/lib/Analysis/SimpleConstraintManager.cpp @@ -15,6 +15,7 @@ #include "SimpleConstraintManager.h" #include "clang/Analysis/PathSensitive/GRExprEngine.h" #include "clang/Analysis/PathSensitive/GRState.h" +#include "clang/Analysis/PathSensitive/Checker.h" namespace clang { @@ -72,8 +73,17 @@ const GRState *SimpleConstraintManager::Assume(const GRState *state, Loc Cond, // EvalAssume is used to call into the GRTransferFunction object to perform // any checker-specific update of the state based on this assumption being // true or false. - return state ? state->getTransferFuncs().EvalAssume(state, Cond, Assumption) - : NULL; + + if (!state) + return 0; + + std::vector<std::pair<void *, Checker*> >::iterator + I = state->checker_begin(), E = state->checker_end(); + + for (; I != E; ++I) { + state = I->second->EvalAssume(state, Cond, Assumption); + } + return state->getTransferFuncs().EvalAssume(state, Cond, Assumption); } const GRState *SimpleConstraintManager::AssumeAux(const GRState *state, @@ -128,8 +138,18 @@ const GRState *SimpleConstraintManager::Assume(const GRState *state, // EvalAssume is used to call into the GRTransferFunction object to perform // any checker-specific update of the state based on this assumption being // true or false. - return state ? state->getTransferFuncs().EvalAssume(state, Cond, Assumption) - : NULL; + + if (!state) + return 0; + + std::vector<std::pair<void *, Checker*> >::iterator + I = state->checker_begin(), E = state->checker_end(); + + for (; I != E; ++I) { + state = I->second->EvalAssume(state, Cond, Assumption); + } + + return state->getTransferFuncs().EvalAssume(state, Cond, Assumption); } const GRState *SimpleConstraintManager::AssumeAux(const GRState *state, diff --git a/lib/Analysis/Store.cpp b/lib/Analysis/Store.cpp index e6ff6e5af47f4..8d911b844fc04 100644 --- a/lib/Analysis/Store.cpp +++ b/lib/Analysis/Store.cpp @@ -98,7 +98,6 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) } case MemRegion::StringRegionKind: - case MemRegion::ObjCObjectRegionKind: // FIXME: Need to handle arbitrary downcasts. case MemRegion::SymbolicRegionKind: case MemRegion::AllocaRegionKind: @@ -106,6 +105,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) case MemRegion::FieldRegionKind: case MemRegion::ObjCIvarRegionKind: case MemRegion::VarRegionKind: + case MemRegion::CXXObjectRegionKind: return MakeElementRegion(R, PointeeTy); case MemRegion::ElementRegionKind: { @@ -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; } @@ -230,3 +240,8 @@ SVal StoreManager::getLValueCompoundLiteral(const CompoundLiteralExpr* CL, const LocationContext *LC) { return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)); } + +Loc StoreManager::getThisObject(QualType T) { + const CXXObjectRegion *R = MRMgr.getCXXObjectRegion(T); + return loc::MemRegionVal(R); +} |