aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core/ExprEngine.cpp')
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngine.cpp153
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() {