diff options
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core/ExprEngine.cpp')
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 153 |
1 files changed, 103 insertions, 50 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 265dcd134213..f285b652c175 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -169,7 +169,7 @@ public: if (S) { S->printJson(Out, Helper, PP, /*AddQuotes=*/true); } else { - Out << '\"' << I->getAnyMember()->getNameAsString() << '\"'; + Out << '\"' << I->getAnyMember()->getDeclName() << '\"'; } } @@ -2129,6 +2129,83 @@ static const Stmt *ResolveCondition(const Stmt *Condition, llvm_unreachable("could not resolve condition"); } +using ObjCForLctxPair = + std::pair<const ObjCForCollectionStmt *, const LocationContext *>; + +REGISTER_MAP_WITH_PROGRAMSTATE(ObjCForHasMoreIterations, ObjCForLctxPair, bool) + +ProgramStateRef ExprEngine::setWhetherHasMoreIteration( + ProgramStateRef State, const ObjCForCollectionStmt *O, + const LocationContext *LC, bool HasMoreIteraton) { + assert(!State->contains<ObjCForHasMoreIterations>({O, LC})); + return State->set<ObjCForHasMoreIterations>({O, LC}, HasMoreIteraton); +} + +ProgramStateRef +ExprEngine::removeIterationState(ProgramStateRef State, + const ObjCForCollectionStmt *O, + const LocationContext *LC) { + assert(State->contains<ObjCForHasMoreIterations>({O, LC})); + return State->remove<ObjCForHasMoreIterations>({O, LC}); +} + +bool ExprEngine::hasMoreIteration(ProgramStateRef State, + const ObjCForCollectionStmt *O, + const LocationContext *LC) { + assert(State->contains<ObjCForHasMoreIterations>({O, LC})); + return *State->get<ObjCForHasMoreIterations>({O, LC}); +} + +/// Split the state on whether there are any more iterations left for this loop. +/// Returns a (HasMoreIteration, HasNoMoreIteration) pair, or None when the +/// acquisition of the loop condition value failed. +static Optional<std::pair<ProgramStateRef, ProgramStateRef>> +assumeCondition(const Stmt *Condition, ExplodedNode *N) { + ProgramStateRef State = N->getState(); + if (const auto *ObjCFor = dyn_cast<ObjCForCollectionStmt>(Condition)) { + bool HasMoreIteraton = + ExprEngine::hasMoreIteration(State, ObjCFor, N->getLocationContext()); + // Checkers have already ran on branch conditions, so the current + // information as to whether the loop has more iteration becomes outdated + // after this point. + State = ExprEngine::removeIterationState(State, ObjCFor, + N->getLocationContext()); + if (HasMoreIteraton) + return std::pair<ProgramStateRef, ProgramStateRef>{State, nullptr}; + else + return std::pair<ProgramStateRef, ProgramStateRef>{nullptr, State}; + } + SVal X = State->getSVal(Condition, N->getLocationContext()); + + if (X.isUnknownOrUndef()) { + // Give it a chance to recover from unknown. + if (const auto *Ex = dyn_cast<Expr>(Condition)) { + if (Ex->getType()->isIntegralOrEnumerationType()) { + // Try to recover some path-sensitivity. Right now casts of symbolic + // integers that promote their values are currently not tracked well. + // If 'Condition' is such an expression, try and recover the + // underlying value and use that instead. + SVal recovered = + RecoverCastedSymbol(State, Condition, N->getLocationContext(), + N->getState()->getStateManager().getContext()); + + if (!recovered.isUnknown()) { + X = recovered; + } + } + } + } + + // If the condition is still unknown, give up. + if (X.isUnknownOrUndef()) + return None; + + DefinedSVal V = X.castAs<DefinedSVal>(); + + ProgramStateRef StTrue, StFalse; + return State->assume(V); +} + void ExprEngine::processBranch(const Stmt *Condition, NodeBuilderContext& BldCtx, ExplodedNode *Pred, @@ -2165,48 +2242,28 @@ void ExprEngine::processBranch(const Stmt *Condition, return; BranchNodeBuilder builder(CheckersOutSet, Dst, BldCtx, DstT, DstF); - for (const auto PredI : CheckersOutSet) { - if (PredI->isSink()) + for (ExplodedNode *PredN : CheckersOutSet) { + if (PredN->isSink()) continue; - ProgramStateRef PrevState = PredI->getState(); - SVal X = PrevState->getSVal(Condition, PredI->getLocationContext()); - - if (X.isUnknownOrUndef()) { - // Give it a chance to recover from unknown. - if (const auto *Ex = dyn_cast<Expr>(Condition)) { - if (Ex->getType()->isIntegralOrEnumerationType()) { - // Try to recover some path-sensitivity. Right now casts of symbolic - // integers that promote their values are currently not tracked well. - // If 'Condition' is such an expression, try and recover the - // underlying value and use that instead. - SVal recovered = RecoverCastedSymbol(PrevState, Condition, - PredI->getLocationContext(), - getContext()); - - if (!recovered.isUnknown()) { - X = recovered; - } - } - } - } + ProgramStateRef PrevState = PredN->getState(); - // If the condition is still unknown, give up. - if (X.isUnknownOrUndef()) { - builder.generateNode(PrevState, true, PredI); - builder.generateNode(PrevState, false, PredI); + ProgramStateRef StTrue, StFalse; + if (const auto KnownCondValueAssumption = assumeCondition(Condition, PredN)) + std::tie(StTrue, StFalse) = *KnownCondValueAssumption; + else { + assert(!isa<ObjCForCollectionStmt>(Condition)); + builder.generateNode(PrevState, true, PredN); + builder.generateNode(PrevState, false, PredN); continue; } - - DefinedSVal V = X.castAs<DefinedSVal>(); - - ProgramStateRef StTrue, StFalse; - std::tie(StTrue, StFalse) = PrevState->assume(V); + if (StTrue && StFalse) + assert(!isa<ObjCForCollectionStmt>(Condition));; // Process the true branch. if (builder.isFeasible(true)) { if (StTrue) - builder.generateNode(StTrue, true, PredI); + builder.generateNode(StTrue, true, PredN); else builder.markInfeasible(true); } @@ -2214,7 +2271,7 @@ void ExprEngine::processBranch(const Stmt *Condition, // Process the false branch. if (builder.isFeasible(false)) { if (StFalse) - builder.generateNode(StFalse, false, PredI); + builder.generateNode(StFalse, false, PredN); else builder.markInfeasible(false); } @@ -2530,16 +2587,8 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, return; } if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D)) { - // FIXME: Compute lvalue of field pointers-to-member. - // Right now we just use a non-null void pointer, so that it gives proper - // results in boolean contexts. - // FIXME: Maybe delegate this to the surrounding operator&. - // Note how this expression is lvalue, however pointer-to-member is NonLoc. - SVal V = svalBuilder.conjureSymbolVal(Ex, LCtx, getContext().VoidPtrTy, - currBldrCtx->blockCount()); - state = state->assume(V.castAs<DefinedOrUnknownSVal>(), true); - Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr, - ProgramPoint::PostLValueKind); + // Delegate all work related to pointer to members to the surrounding + // operator&. return; } if (isa<BindingDecl>(D)) { @@ -3100,7 +3149,7 @@ struct DOTGraphTraits<ExplodedGraph*> : public DefaultDOTGraphTraits { if (Stop(N)) return true; - if (N->succ_size() != 1 || !isNodeHidden(N->getFirstSucc())) + if (N->succ_size() != 1 || !isNodeHidden(N->getFirstSucc(), nullptr)) break; PostCallback(N); @@ -3109,7 +3158,7 @@ struct DOTGraphTraits<ExplodedGraph*> : public DefaultDOTGraphTraits { return false; } - static bool isNodeHidden(const ExplodedNode *N) { + static bool isNodeHidden(const ExplodedNode *N, const ExplodedGraph *G) { return N->isTrivial(); } @@ -3162,8 +3211,9 @@ void ExprEngine::ViewGraph(bool trim) { #ifndef NDEBUG std::string Filename = DumpGraph(trim); llvm::DisplayGraph(Filename, false, llvm::GraphProgram::DOT); -#endif +#else llvm::errs() << "Warning: viewing graph requires assertions" << "\n"; +#endif } @@ -3171,8 +3221,9 @@ void ExprEngine::ViewGraph(ArrayRef<const ExplodedNode*> Nodes) { #ifndef NDEBUG std::string Filename = DumpGraph(Nodes); llvm::DisplayGraph(Filename, false, llvm::GraphProgram::DOT); -#endif +#else llvm::errs() << "Warning: viewing graph requires assertions" << "\n"; +#endif } std::string ExprEngine::DumpGraph(bool trim, StringRef Filename) { @@ -3209,15 +3260,17 @@ std::string ExprEngine::DumpGraph(ArrayRef<const ExplodedNode*> Nodes, if (!TrimmedG.get()) { llvm::errs() << "warning: Trimmed ExplodedGraph is empty.\n"; + return ""; } else { return llvm::WriteGraph(TrimmedG.get(), "TrimmedExprEngine", /*ShortNames=*/false, /*Title=*/"Trimmed Exploded Graph", /*Filename=*/std::string(Filename)); } -#endif +#else llvm::errs() << "Warning: dumping graph requires assertions" << "\n"; return ""; +#endif } void *ProgramStateTrait<ReplayWithoutInlining>::GDMIndex() { |