aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2012-07-26 22:23:41 +0000
committerTed Kremenek <kremenek@apple.com>2012-07-26 22:23:41 +0000
commit6da60499eae46caf9f92f7ba35c607043dc3f7fa (patch)
treec6b2c108dcae73481e723afd54651f968a13f2da
parent7c99aa385178c630e29f671299cdd9c104f1c885 (diff)
Look at the preceding CFGBlock for the expression to load from in ExprEngine::VisitGuardedExpr
instead of walking to the preceding PostStmt node. There are cases where the last evaluated expression does not appear in the ExplodedGraph. Fixes PR 13466. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@160819 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineC.cpp36
-rw-r--r--test/Analysis/misc-ps.m18
2 files changed, 43 insertions, 11 deletions
diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index fd467c2b7a..7ec151ef6d 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -593,22 +593,36 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex,
StmtNodeBuilder B(Pred, Dst, *currentBuilderContext);
ProgramStateRef state = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
+ const CFGBlock *SrcBlock = 0;
- // Assume that the last CFGElement visited is the value of
- // the guarded expression.
- ExplodedNode *N = Pred;
+ for (const ExplodedNode *N = Pred ; N ; N = *N->pred_begin()) {
+ ProgramPoint PP = N->getLocation();
+ if (isa<PreStmtPurgeDeadSymbols>(PP) || isa<BlockEntrance>(PP)) {
+ assert(N->pred_size() == 1);
+ continue;
+ }
+ SrcBlock = cast<BlockEdge>(&PP)->getSrc();
+ break;
+ }
+
+ // Find the last expression in the predecessor block. That is the
+ // expression that is used for the value of the ternary expression.
+ bool hasValue = false;
SVal V;
- while (N) {
- ProgramPoint P = N->getLocation();
- if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) {
- const Expr *Ex = cast<Expr>(PS->getStmt());
- V = state->getSVal(Ex, LCtx);
+
+ for (CFGBlock::const_reverse_iterator I = SrcBlock->rbegin(),
+ E = SrcBlock->rend(); I != E; ++I) {
+ CFGElement CE = *I;
+ if (CFGStmt *CS = dyn_cast<CFGStmt>(&CE)) {
+ const Expr *ValEx = cast<Expr>(CS->getStmt());
+ hasValue = true;
+ V = state->getSVal(ValEx, LCtx);
break;
}
- assert(N->pred_size() == 1);
- N = *N->pred_begin();
}
- assert(N);
+
+ assert(hasValue);
+ (void) hasValue;
// Generate a new node with the binding from the appropriate path.
B.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V, true));
diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m
index c22837e4e6..edc1e1f94d 100644
--- a/test/Analysis/misc-ps.m
+++ b/test/Analysis/misc-ps.m
@@ -1356,3 +1356,21 @@ void radar9414427() {
}
@end
+// Don't crash when a ?: is only preceded by a statement (not an expression)
+// in the CFG.
+void __assert_fail();
+
+enum rdar1196620_e { E_A, E_B, E_C, E_D };
+struct rdar1196620_s { int ints[E_D+1]; };
+
+static int rdar1196620_call_assert(struct rdar1196620_s* s) {
+ int i = 0;
+ s?(void)0:__assert_fail();
+}
+
+static void rdar1196620(struct rdar1196620_s* s) {
+ if (rdar1196620_call_assert(s))
+ return;
+}
+
+