Index: include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h =================================================================== --- include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h +++ include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h @@ -142,13 +142,15 @@ /// Scan all symbols referenced by the constraints. If the symbol is not /// alive, remove it. virtual ProgramStateRef removeDeadBindings(ProgramStateRef state, - SymbolReaper& SymReaper) = 0; + SymbolReaper &SymReaper) = 0; - virtual void print(ProgramStateRef state, - raw_ostream &Out, - const char* nl, + virtual void print(ProgramStateRef state, raw_ostream &Out, const char *nl, const char *sep) = 0; + virtual ProgramStateRef evalRangeOp(ProgramStateRef state, SVal V) { + return nullptr; + } + virtual void EndPath(ProgramStateRef state) {} /// Convenience method to query the state to see if a symbol is null or Index: lib/StaticAnalyzer/Core/ExprEngineC.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -98,7 +98,9 @@ } state = state->BindExpr(B, LCtx, Result); - Bldr.generateNode(B, *it, state); + ProgramStateRef state2 = + getConstraintManager().evalRangeOp(state, Result); + Bldr.generateNode(B, *it, state2 ? state2 : state); continue; } Index: lib/StaticAnalyzer/Core/RangeConstraintManager.cpp =================================================================== --- lib/StaticAnalyzer/Core/RangeConstraintManager.cpp +++ lib/StaticAnalyzer/Core/RangeConstraintManager.cpp @@ -304,6 +304,8 @@ void print(ProgramStateRef State, raw_ostream &Out, const char *nl, const char *sep) override; + ProgramStateRef evalRangeOp(ProgramStateRef state, SVal V) override; + //===------------------------------------------------------------------===// // Implementation for interface from RangedConstraintManager. //===------------------------------------------------------------------===// @@ -741,3 +743,65 @@ } Out << nl; } + +ProgramStateRef RangeConstraintManager::evalRangeOp(ProgramStateRef St, + SVal V) { + const SymExpr *SE = V.getAsSymExpr(); + if (!SE) + return nullptr; + + const SymIntExpr *SIE = dyn_cast(SE); + if (!SIE) + return nullptr; + + const clang::BinaryOperatorKind Opc = SIE->getOpcode(); + + if (Opc != BO_Add && Opc != BO_Sub && Opc != BO_Div) + return nullptr; + + const SymExpr *LHS = SIE->getLHS(); + const llvm::APSInt &RHS = SIE->getRHS(); + + if (RHS.isNegative()) + // TODO: Handle negative values. + return nullptr; + + ConstraintRangeTy Ranges = St->get(); + for (ConstraintRangeTy::iterator I = Ranges.begin(), E = Ranges.end(); I != E; + ++I) { + if (LHS == I.getKey()) { + const auto D = I.getData(); + for (auto I = D.begin(); I != D.end(); ++I) { + if (I->From().isUnsigned() != RHS.isUnsigned()) + // TODO: Handle sign conversions. + return nullptr; + if (I->From().getBitWidth() != RHS.getBitWidth()) + // TODO: Promote values. + return nullptr; + if (I->From().isNegative()) + // TODO: Handle negative range values + return nullptr; + llvm::APSInt Lower; + llvm::APSInt Upper; + if (Opc == BO_Add) { + Lower = I->From() + RHS; + Upper = I->To() + RHS; + } else if (Opc == BO_Sub) { + if (RHS > I->From()) + return nullptr; + Lower = I->From() - RHS; + Upper = I->To() - RHS; + } else if (Opc == BO_Div) { + Lower = I->From() / RHS; + Upper = I->To() / RHS; + } + SymbolRef Sym = V.getAsSymbol(); + RangeSet RS = + getRange(St, Sym).Intersect(getBasicVals(), F, Lower, Upper); + // TODO: This only evaluates the first range. Evaluate all ranges. + return RS.isEmpty() ? nullptr : St->set(Sym, RS); + } + } + } + return nullptr; +} Index: test/Analysis/eval-range.c =================================================================== --- test/Analysis/eval-range.c +++ test/Analysis/eval-range.c @@ -0,0 +1,18 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s + +void clang_analyzer_eval(int); + +void test1(int a) { + if (a >= 10 && a <= 50) { + int b; + + b = a + 2; + clang_analyzer_eval(b >= 12 && b <= 52); // expected-warning{{TRUE}} + + b = a - 2; + clang_analyzer_eval(b >= 8 && b <= 48); // expected-warning{{TRUE}} + + b = a / 2; + clang_analyzer_eval(b >= 5 && b <= 25); // expected-warning{{TRUE}} + } +}