diff options
author | Manuel Klimek <klimek@google.com> | 2014-05-05 09:58:03 +0000 |
---|---|---|
committer | Manuel Klimek <klimek@google.com> | 2014-05-05 09:58:03 +0000 |
commit | 264f963114e475666ee1841502f3a1fdd74e81e9 (patch) | |
tree | c72ee97715b217de6fc42d232b155a695860d064 /clang/lib/StaticAnalyzer | |
parent | 918d1097a136b487e9ef0a7aa63f50d7b30a773a (diff) | |
download | bcm5719-llvm-264f963114e475666ee1841502f3a1fdd74e81e9.tar.gz bcm5719-llvm-264f963114e475666ee1841502f3a1fdd74e81e9.zip |
Fix crash when resolving branch conditions for temporary destructor condition blocks.
Document and simplify ResolveCondition.
1. Introduce a temporary special case for temporary desctructors when resolving
the branch condition - in an upcoming patch, alexmc will change temporary
destructor conditions to not run through this logic, in which case we can remove
this (marked as FIXME); this currently fixes a crash.
2. Simplify ResolveCondition; while documenting the function, I noticed that it
always returns the last statement - either that statement is the condition
itself (in which case the condition was returned anyway), or the rightmost
leaf is returned; for correctness, the rightmost leaf must be evaluated anyway
(which the CFG does in the last statement), thus we can just return the last
statement in that case, too. Added an assert to verify the invariant.
llvm-svn: 207957
Diffstat (limited to 'clang/lib/StaticAnalyzer')
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 46 |
1 files changed, 34 insertions, 12 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index fd77e710b83..b582749a02a 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1352,6 +1352,31 @@ static SVal RecoverCastedSymbol(ProgramStateManager& StateMgr, return state->getSVal(Ex, LCtx); } +const Stmt *getRightmostLeaf(const Stmt *Condition) { + while (Condition) { + const BinaryOperator *BO = dyn_cast<BinaryOperator>(Condition); + if (!BO || !BO->isLogicalOp()) { + return Condition; + } + Condition = BO->getRHS()->IgnoreParens(); + } + return nullptr; +} + +// Returns the condition the branch at the end of 'B' depends on and whose value +// has been evaluated within 'B'. +// In most cases, the terminator condition of 'B' will be evaluated fully in +// the last statement of 'B'; in those cases, the resolved condition is the +// given 'Condition'. +// If the condition of the branch is a logical binary operator tree, the CFG is +// optimized: in that case, we know that the expression formed by all but the +// rightmost leaf of the logical binary operator tree must be true, and thus +// the branch condition is at this point equivalent to the truth value of that +// rightmost leaf; the CFG block thus only evaluates this rightmost leaf +// expression in its final statement. As the full condition in that case was +// not evaluated, and is thus not in the SVal cache, we need to use that leaf +// expression to evaluate the truth value of the condition in the current state +// space. static const Stmt *ResolveCondition(const Stmt *Condition, const CFGBlock *B) { if (const Expr *Ex = dyn_cast<Expr>(Condition)) @@ -1361,6 +1386,12 @@ 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; + // For logical operations, we still have the case where some branches // use the traditional "merge" approach and others sink the branch // directly into the basic blocks representing the logical operation. @@ -1375,18 +1406,9 @@ static const Stmt *ResolveCondition(const Stmt *Condition, Optional<CFGStmt> CS = Elem.getAs<CFGStmt>(); if (!CS) continue; - if (CS->getStmt() != Condition) - break; - return Condition; - } - - assert(I != E); - - while (Condition) { - BO = dyn_cast<BinaryOperator>(Condition); - if (!BO || !BO->isLogicalOp()) - return Condition; - Condition = BO->getRHS()->IgnoreParens(); + const Stmt *LastStmt = CS->getStmt(); + assert(LastStmt == Condition || LastStmt == getRightmostLeaf(Condition)); + return LastStmt; } llvm_unreachable("could not resolve condition"); } |