diff options
Diffstat (limited to 'lib/StaticAnalyzer/Core/ExprEngine.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngine.cpp | 125 |
1 files changed, 114 insertions, 11 deletions
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 4e4095c..4699df8 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -51,6 +51,15 @@ STATISTIC(NumMaxBlockCountReachedInInlined, STATISTIC(NumTimesRetriedWithoutInlining, "The # of times we re-evaluated a call without inlining"); +typedef std::pair<const CXXBindTemporaryExpr *, const StackFrameContext *> + CXXBindTemporaryContext; + +// Keeps track of whether CXXBindTemporaryExpr nodes have been evaluated. +// The StackFrameContext assures that nested calls due to inlined recursive +// functions do not interfere. +REGISTER_TRAIT_WITH_PROGRAMSTATE(InitializedTemporariesSet, + llvm::ImmutableSet<CXXBindTemporaryContext>) + //===----------------------------------------------------------------------===// // Engine construction and deletion. //===----------------------------------------------------------------------===// @@ -659,13 +668,71 @@ void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D, void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D, ExplodedNode *Pred, ExplodedNodeSet &Dst) { + ExplodedNodeSet CleanDtorState; + StmtNodeBuilder StmtBldr(Pred, CleanDtorState, *currBldrCtx); + ProgramStateRef State = Pred->getState(); + if (State->contains<InitializedTemporariesSet>( + std::make_pair(D.getBindTemporaryExpr(), Pred->getStackFrame()))) { + // FIXME: Currently we insert temporary destructors for default parameters, + // but we don't insert the constructors. + State = State->remove<InitializedTemporariesSet>( + std::make_pair(D.getBindTemporaryExpr(), Pred->getStackFrame())); + } + StmtBldr.generateNode(D.getBindTemporaryExpr(), Pred, State); QualType varType = D.getBindTemporaryExpr()->getSubExpr()->getType(); - - // FIXME: Inlining of temporary destructors is not supported yet anyway, so we - // just put a NULL region for now. This will need to be changed later. + // FIXME: Currently CleanDtorState can be empty here due to temporaries being + // bound to default parameters. + assert(CleanDtorState.size() <= 1); + ExplodedNode *CleanPred = + CleanDtorState.empty() ? Pred : *CleanDtorState.begin(); + // FIXME: Inlining of temporary destructors is not supported yet anyway, so + // we just put a NULL region for now. This will need to be changed later. VisitCXXDestructor(varType, nullptr, D.getBindTemporaryExpr(), - /*IsBase=*/ false, Pred, Dst); + /*IsBase=*/false, CleanPred, Dst); +} + +void ExprEngine::processCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE, + NodeBuilderContext &BldCtx, + ExplodedNode *Pred, + ExplodedNodeSet &Dst, + const CFGBlock *DstT, + const CFGBlock *DstF) { + BranchNodeBuilder TempDtorBuilder(Pred, Dst, BldCtx, DstT, DstF); + if (Pred->getState()->contains<InitializedTemporariesSet>( + std::make_pair(BTE, Pred->getStackFrame()))) { + TempDtorBuilder.markInfeasible(false); + TempDtorBuilder.generateNode(Pred->getState(), true, Pred); + } else { + TempDtorBuilder.markInfeasible(true); + TempDtorBuilder.generateNode(Pred->getState(), false, Pred); + } +} + +void ExprEngine::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE, + ExplodedNodeSet &PreVisit, + ExplodedNodeSet &Dst) { + if (!getAnalysisManager().options.includeTemporaryDtorsInCFG()) { + // In case we don't have temporary destructors in the CFG, do not mark + // the initialization - we would otherwise never clean it up. + Dst = PreVisit; + return; + } + StmtNodeBuilder StmtBldr(PreVisit, Dst, *currBldrCtx); + for (ExplodedNode *Node : PreVisit) { + ProgramStateRef State = Node->getState(); + + if (!State->contains<InitializedTemporariesSet>( + std::make_pair(BTE, Node->getStackFrame()))) { + // FIXME: Currently the state might already contain the marker due to + // incorrect handling of temporaries bound to default parameters; for + // those, we currently skip the CXXBindTemporaryExpr but rely on adding + // temporary destructor nodes. + State = State->add<InitializedTemporariesSet>( + std::make_pair(BTE, Node->getStackFrame())); + } + StmtBldr.generateNode(BTE, Node, State); + } } void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, @@ -685,6 +752,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::CXXTryStmtClass: case Stmt::CXXTypeidExprClass: case Stmt::CXXUuidofExprClass: + case Stmt::CXXFoldExprClass: case Stmt::MSPropertyRefExprClass: case Stmt::CXXUnresolvedConstructExprClass: case Stmt::DependentScopeDeclRefExprClass: @@ -693,6 +761,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::ExpressionTraitExprClass: case Stmt::UnresolvedLookupExprClass: case Stmt::UnresolvedMemberExprClass: + case Stmt::TypoExprClass: case Stmt::CXXNoexceptExprClass: case Stmt::PackExpansionExprClass: case Stmt::SubstNonTypeTemplateParmPackExprClass: @@ -734,18 +803,24 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::OMPParallelDirectiveClass: case Stmt::OMPSimdDirectiveClass: case Stmt::OMPForDirectiveClass: + case Stmt::OMPForSimdDirectiveClass: case Stmt::OMPSectionsDirectiveClass: case Stmt::OMPSectionDirectiveClass: case Stmt::OMPSingleDirectiveClass: case Stmt::OMPMasterDirectiveClass: case Stmt::OMPCriticalDirectiveClass: case Stmt::OMPParallelForDirectiveClass: + case Stmt::OMPParallelForSimdDirectiveClass: case Stmt::OMPParallelSectionsDirectiveClass: case Stmt::OMPTaskDirectiveClass: case Stmt::OMPTaskyieldDirectiveClass: case Stmt::OMPBarrierDirectiveClass: case Stmt::OMPTaskwaitDirectiveClass: case Stmt::OMPFlushDirectiveClass: + case Stmt::OMPOrderedDirectiveClass: + case Stmt::OMPAtomicDirectiveClass: + case Stmt::OMPTargetDirectiveClass: + case Stmt::OMPTeamsDirectiveClass: llvm_unreachable("Stmt should not be in analyzer evaluation loop"); case Stmt::ObjCSubscriptRefExprClass: @@ -771,6 +846,17 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, // Handled due to fully linearised CFG. break; + case Stmt::CXXBindTemporaryExprClass: { + Bldr.takeNodes(Pred); + ExplodedNodeSet PreVisit; + getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this); + ExplodedNodeSet Next; + VisitCXXBindTemporaryExpr(cast<CXXBindTemporaryExpr>(S), PreVisit, Next); + getCheckerManager().runCheckersForPostStmt(Dst, Next, S, *this); + Bldr.addNodes(Dst); + break; + } + // Cases not handled yet; but will handle some day. case Stmt::DesignatedInitExprClass: case Stmt::ExtVectorElementExprClass: @@ -784,7 +870,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::ObjCProtocolExprClass: case Stmt::ObjCSelectorExprClass: case Stmt::ParenListExprClass: - case Stmt::PredefinedExprClass: case Stmt::ShuffleVectorExprClass: case Stmt::ConvertVectorExprClass: case Stmt::VAArgExprClass: @@ -796,6 +881,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, // Cases we intentionally don't evaluate, since they don't need // to be explicitly evaluated. + case Stmt::PredefinedExprClass: case Stmt::AddrLabelExprClass: case Stmt::AttributedStmtClass: case Stmt::IntegerLiteralClass: @@ -808,7 +894,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::SizeOfPackExprClass: case Stmt::StringLiteralClass: case Stmt::ObjCStringLiteralClass: - case Stmt::CXXBindTemporaryExprClass: case Stmt::CXXPseudoDestructorExprClass: case Stmt::SubstNonTypeTemplateParmExprClass: case Stmt::CXXNullPtrLiteralExprClass: { @@ -1403,11 +1488,8 @@ static const Stmt *ResolveCondition(const Stmt *Condition, if (!BO || !BO->isLogicalOp()) return Condition; - // FIXME: This is a workaround until we handle temporary destructor branches - // correctly; currently, temporary destructor branches lead to blocks that - // only have a terminator (and no statements). These blocks violate the - // invariant this function assumes. - if (B->getTerminator().isTemporaryDtorsBranch()) return Condition; + assert(!B->getTerminator().isTemporaryDtorsBranch() && + "Temporary destructor branches handled by processBindTemporary."); // For logical operations, we still have the case where some branches // use the traditional "merge" approach and others sink the branch @@ -1436,6 +1518,8 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term, ExplodedNodeSet &Dst, const CFGBlock *DstT, const CFGBlock *DstF) { + assert((!Condition || !isa<CXXBindTemporaryExpr>(Condition)) && + "CXXBindTemporaryExprs are handled by processBindTemporary."); const LocationContext *LCtx = Pred->getLocationContext(); PrettyStackTraceLocationContext StackCrashInfo(LCtx); currBldrCtx = &BldCtx; @@ -1599,10 +1683,29 @@ void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) { builder.generateNode(I, state); } +#if 0 +static bool stackFrameDoesNotContainInitializedTemporaries(ExplodedNode &Pred) { + const StackFrameContext* Frame = Pred.getStackFrame(); + const llvm::ImmutableSet<CXXBindTemporaryContext> &Set = + Pred.getState()->get<InitializedTemporariesSet>(); + return std::find_if(Set.begin(), Set.end(), + [&](const CXXBindTemporaryContext &Ctx) { + if (Ctx.second == Frame) { + Ctx.first->dump(); + llvm::errs() << "\n"; + } + return Ctx.second == Frame; + }) == Set.end(); +} +#endif + /// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path /// nodes when the control reaches the end of a function. void ExprEngine::processEndOfFunction(NodeBuilderContext& BC, ExplodedNode *Pred) { + // FIXME: Assert that stackFrameDoesNotContainInitializedTemporaries(*Pred)). + // We currently cannot enable this assert, as lifetime extended temporaries + // are not modelled correctly. PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext()); StateMgr.EndPath(Pred->getState()); |