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,56 @@ } 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(); + + ConstraintRangeTy Ranges = St->get(); + for (ConstraintRangeTy::iterator I = Ranges.begin(), E = Ranges.end(); I != E; + ++I) { + if (LHS != I.getKey()) + continue; + 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; + + BasicValueFactory &BVF = getBasicVals(); + const llvm::APSInt *Lower = BVF.evalAPSInt(Opc, I->From(), RHS); + if (!Lower) + return nullptr; + const llvm::APSInt *Upper = BVF.evalAPSInt(Opc, I->To(), RHS); + if (!Upper) + return nullptr; + + 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; +}