diff options
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngineC.cpp | 24 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/SValBuilder.cpp | 17 | ||||
-rw-r--r-- | test/Analysis/conditional-operator.cpp | 17 |
3 files changed, 49 insertions, 9 deletions
diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 7a53fccf2e..2d52c01e1d 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -617,11 +617,15 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex, const Expr *R, ExplodedNode *Pred, ExplodedNodeSet &Dst) { + assert(L && R); + StmtNodeBuilder B(Pred, Dst, *currBldrCtx); ProgramStateRef state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); const CFGBlock *SrcBlock = 0; + // Find the predecessor block. + ProgramStateRef SrcState = state; for (const ExplodedNode *N = Pred ; N ; N = *N->pred_begin()) { ProgramPoint PP = N->getLocation(); if (PP.getAs<PreStmtPurgeDeadSymbols>() || PP.getAs<BlockEntrance>()) { @@ -629,6 +633,7 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex, continue; } SrcBlock = PP.castAs<BlockEdge>().getSrc(); + SrcState = N->getState(); break; } @@ -644,14 +649,25 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex, CFGElement CE = *I; if (Optional<CFGStmt> CS = CE.getAs<CFGStmt>()) { const Expr *ValEx = cast<Expr>(CS->getStmt()); - hasValue = true; - V = state->getSVal(ValEx, LCtx); + ValEx = ValEx->IgnoreParens(); + + // For GNU extension '?:' operator, the left hand side will be an + // OpaqueValueExpr, so get the underlying expression. + if (const OpaqueValueExpr *OpaqueEx = dyn_cast<OpaqueValueExpr>(L)) + L = OpaqueEx->getSourceExpr(); + + // If the last expression in the predecessor block matches true or false + // subexpression, get its the value. + if (ValEx == L->IgnoreParens() || ValEx == R->IgnoreParens()) { + hasValue = true; + V = SrcState->getSVal(ValEx, LCtx); + } break; } } - assert(hasValue); - (void) hasValue; + if (!hasValue) + V = svalBuilder.conjureSymbolVal(0, Ex, LCtx, currBldrCtx->blockCount()); // Generate a new node with the binding from the appropriate path. B.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V, true)); diff --git a/lib/StaticAnalyzer/Core/SValBuilder.cpp b/lib/StaticAnalyzer/Core/SValBuilder.cpp index 19a4353ffc..309230ebed 100644 --- a/lib/StaticAnalyzer/Core/SValBuilder.cpp +++ b/lib/StaticAnalyzer/Core/SValBuilder.cpp @@ -106,12 +106,19 @@ SValBuilder::getRegionValueSymbolVal(const TypedValueRegion* region) { return nonloc::SymbolVal(sym); } -DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *symbolTag, - const Expr *expr, +DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *SymbolTag, + const Expr *Ex, const LocationContext *LCtx, - unsigned count) { - QualType T = expr->getType(); - return conjureSymbolVal(symbolTag, expr, LCtx, T, count); + unsigned Count) { + QualType T = Ex->getType(); + + // Compute the type of the result. If the expression is not an R-value, the + // result should be a location. + QualType ExType = Ex->getType(); + if (Ex->isGLValue()) + T = LCtx->getAnalysisDeclContext()->getASTContext().getPointerType(ExType); + + return conjureSymbolVal(SymbolTag, Ex, LCtx, T, Count); } DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *symbolTag, diff --git a/test/Analysis/conditional-operator.cpp b/test/Analysis/conditional-operator.cpp new file mode 100644 index 0000000000..5a3c325b91 --- /dev/null +++ b/test/Analysis/conditional-operator.cpp @@ -0,0 +1,17 @@ +// RUN: %clang -cc1 -analyze -analyzer-checker=core,debug.ExprInspection %s -analyzer-output=text -verify + +void clang_analyzer_eval(bool); + +// Test that the analyzer does not crash on GNU extension operator "?:". +void NoCrashTest(int x, int y) { + int w = x ?: y; +} + +void OperatorEvaluationTest(int y) { + int x = 1; + int w = x ?: y; // expected-note {{'?' condition is true}} + + // TODO: We are not precise when processing the "?:" operator in C++. + clang_analyzer_eval(w == 1); // expected-warning{{UNKNOWN}} + // expected-note@-1{{UNKNOWN}} +}
\ No newline at end of file |