[cfe-commits] r106339 - in /cfe/trunk: include/clang/AST/Expr.h lib/Checker/BasicConstraintManager.cpp lib/Checker/RangeConstraintManager.cpp lib/Checker/SimpleConstraintManager.cpp lib/Checker/SimpleConstraintManager.h lib/Checker/SimpleSValuator.cpp test/Analysis/additive-folding-range-constraints.c test/Analysis/additive-folding.c
Ted Kremenek
kremenek at apple.com
Fri Jun 18 17:17:50 PDT 2010
Great work Jordy!
On Jun 18, 2010, at 3:49 PM, Jordy Rose wrote:
> Author: jrose
> Date: Fri Jun 18 17:49:11 2010
> New Revision: 106339
>
> URL: http://llvm.org/viewvc/llvm-project?rev=106339&view=rev
> Log:
> Fold additive constants, and support comparsions of the form $sym+const1 <> const2
>
> Added:
> cfe/trunk/test/Analysis/additive-folding-range-constraints.c
> cfe/trunk/test/Analysis/additive-folding.c
> Modified:
> cfe/trunk/include/clang/AST/Expr.h
> cfe/trunk/lib/Checker/BasicConstraintManager.cpp
> cfe/trunk/lib/Checker/RangeConstraintManager.cpp
> cfe/trunk/lib/Checker/SimpleConstraintManager.cpp
> cfe/trunk/lib/Checker/SimpleConstraintManager.h
> cfe/trunk/lib/Checker/SimpleSValuator.cpp
>
> Modified: cfe/trunk/include/clang/AST/Expr.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=106339&r1=106338&r2=106339&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/AST/Expr.h (original)
> +++ cfe/trunk/include/clang/AST/Expr.h Fri Jun 18 17:49:11 2010
> @@ -2169,7 +2169,8 @@
>
> /// predicates to categorize the respective opcodes.
> bool isMultiplicativeOp() const { return Opc >= Mul && Opc <= Rem; }
> - bool isAdditiveOp() const { return Opc == Add || Opc == Sub; }
> + static bool isAdditiveOp(Opcode Opc) { return Opc == Add || Opc == Sub; }
> + bool isAdditiveOp() const { return isAdditiveOp(Opc); }
> static bool isShiftOp(Opcode Opc) { return Opc == Shl || Opc == Shr; }
> bool isShiftOp() const { return isShiftOp(Opc); }
>
>
> Modified: cfe/trunk/lib/Checker/BasicConstraintManager.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/BasicConstraintManager.cpp?rev=106339&r1=106338&r2=106339&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Checker/BasicConstraintManager.cpp (original)
> +++ cfe/trunk/lib/Checker/BasicConstraintManager.cpp Fri Jun 18 17:49:11 2010
> @@ -54,22 +54,28 @@
> ISetFactory(statemgr.getAllocator()) {}
>
> const GRState* AssumeSymNE(const GRState* state, SymbolRef sym,
> - const llvm::APSInt& V);
> + const llvm::APSInt& V,
> + const llvm::APSInt& Adjustment);
>
> const GRState* AssumeSymEQ(const GRState* state, SymbolRef sym,
> - const llvm::APSInt& V);
> + const llvm::APSInt& V,
> + const llvm::APSInt& Adjustment);
>
> const GRState* AssumeSymLT(const GRState* state, SymbolRef sym,
> - const llvm::APSInt& V);
> + const llvm::APSInt& V,
> + const llvm::APSInt& Adjustment);
>
> const GRState* AssumeSymGT(const GRState* state, SymbolRef sym,
> - const llvm::APSInt& V);
> + const llvm::APSInt& V,
> + const llvm::APSInt& Adjustment);
>
> const GRState* AssumeSymGE(const GRState* state, SymbolRef sym,
> - const llvm::APSInt& V);
> + const llvm::APSInt& V,
> + const llvm::APSInt& Adjustment);
>
> const GRState* AssumeSymLE(const GRState* state, SymbolRef sym,
> - const llvm::APSInt& V);
> + const llvm::APSInt& V,
> + const llvm::APSInt& Adjustment);
>
> const GRState* AddEQ(const GRState* state, SymbolRef sym, const llvm::APSInt& V);
>
> @@ -94,46 +100,52 @@
> return new BasicConstraintManager(statemgr, subengine);
> }
>
> +
> const GRState*
> BasicConstraintManager::AssumeSymNE(const GRState *state, SymbolRef sym,
> - const llvm::APSInt& V) {
> - // First, determine if sym == X, where X != V.
> + const llvm::APSInt &V,
> + const llvm::APSInt &Adjustment) {
> + // First, determine if sym == X, where X+Adjustment != V.
> + llvm::APSInt Adjusted = V-Adjustment;
> if (const llvm::APSInt* X = getSymVal(state, sym)) {
> - bool isFeasible = (*X != V);
> + bool isFeasible = (*X != Adjusted);
> return isFeasible ? state : NULL;
> }
>
> - // Second, determine if sym != V.
> - if (isNotEqual(state, sym, V))
> + // Second, determine if sym+Adjustment != V.
> + if (isNotEqual(state, sym, Adjusted))
> return state;
>
> // If we reach here, sym is not a constant and we don't know if it is != V.
> // Make that assumption.
> - return AddNE(state, sym, V);
> + return AddNE(state, sym, Adjusted);
> }
>
> -const GRState *BasicConstraintManager::AssumeSymEQ(const GRState *state,
> - SymbolRef sym,
> - const llvm::APSInt &V) {
> - // First, determine if sym == X, where X != V.
> +const GRState*
> +BasicConstraintManager::AssumeSymEQ(const GRState *state, SymbolRef sym,
> + const llvm::APSInt &V,
> + const llvm::APSInt &Adjustment) {
> + // First, determine if sym == X, where X+Adjustment != V.
> + llvm::APSInt Adjusted = V-Adjustment;
> if (const llvm::APSInt* X = getSymVal(state, sym)) {
> - bool isFeasible = *X == V;
> + bool isFeasible = (*X == Adjusted);
> return isFeasible ? state : NULL;
> }
>
> - // Second, determine if sym != V.
> - if (isNotEqual(state, sym, V))
> + // Second, determine if sym+Adjustment != V.
> + if (isNotEqual(state, sym, Adjusted))
> return NULL;
>
> // If we reach here, sym is not a constant and we don't know if it is == V.
> // Make that assumption.
> - return AddEQ(state, sym, V);
> + return AddEQ(state, sym, Adjusted);
> }
>
> -// These logic will be handled in another ConstraintManager.
> -const GRState *BasicConstraintManager::AssumeSymLT(const GRState *state,
> - SymbolRef sym,
> - const llvm::APSInt& V) {
> +// The logic for these will be handled in another ConstraintManager.
> +const GRState*
> +BasicConstraintManager::AssumeSymLT(const GRState *state, SymbolRef sym,
> + const llvm::APSInt &V,
> + const llvm::APSInt &Adjustment) {
> // Is 'V' the smallest possible value?
> if (V == llvm::APSInt::getMinValue(V.getBitWidth(), V.isUnsigned())) {
> // sym cannot be any value less than 'V'. This path is infeasible.
> @@ -141,13 +153,13 @@
> }
>
> // FIXME: For now have assuming x < y be the same as assuming sym != V;
> - return AssumeSymNE(state, sym, V);
> + return AssumeSymNE(state, sym, V, Adjustment);
> }
>
> -const GRState *BasicConstraintManager::AssumeSymGT(const GRState *state,
> - SymbolRef sym,
> - const llvm::APSInt& V) {
> -
> +const GRState*
> +BasicConstraintManager::AssumeSymGT(const GRState *state, SymbolRef sym,
> + const llvm::APSInt &V,
> + const llvm::APSInt &Adjustment) {
> // Is 'V' the largest possible value?
> if (V == llvm::APSInt::getMaxValue(V.getBitWidth(), V.isUnsigned())) {
> // sym cannot be any value greater than 'V'. This path is infeasible.
> @@ -155,56 +167,60 @@
> }
>
> // FIXME: For now have assuming x > y be the same as assuming sym != V;
> - return AssumeSymNE(state, sym, V);
> + return AssumeSymNE(state, sym, V, Adjustment);
> }
>
> -const GRState *BasicConstraintManager::AssumeSymGE(const GRState *state,
> - SymbolRef sym,
> - const llvm::APSInt &V) {
> -
> - // Reject a path if the value of sym is a constant X and !(X >= V).
> +const GRState*
> +BasicConstraintManager::AssumeSymGE(const GRState *state, SymbolRef sym,
> + const llvm::APSInt &V,
> + const llvm::APSInt &Adjustment) {
> + // Reject a path if the value of sym is a constant X and !(X+Adj >= V).
> if (const llvm::APSInt *X = getSymVal(state, sym)) {
> - bool isFeasible = *X >= V;
> + bool isFeasible = (*X >= V-Adjustment);
> return isFeasible ? state : NULL;
> }
>
> // Sym is not a constant, but it is worth looking to see if V is the
> // maximum integer value.
> if (V == llvm::APSInt::getMaxValue(V.getBitWidth(), V.isUnsigned())) {
> - // If we know that sym != V, then this condition is infeasible since
> - // there is no other value greater than V.
> - bool isFeasible = !isNotEqual(state, sym, V);
> + llvm::APSInt Adjusted = V-Adjustment;
> +
> + // If we know that sym != V (after adjustment), then this condition
> + // is infeasible since there is no other value greater than V.
> + bool isFeasible = !isNotEqual(state, sym, Adjusted);
>
> // If the path is still feasible then as a consequence we know that
> - // 'sym == V' because we cannot have 'sym > V' (no larger values).
> + // 'sym+Adjustment == V' because there are no larger values.
> // Add this constraint.
> - return isFeasible ? AddEQ(state, sym, V) : NULL;
> + return isFeasible ? AddEQ(state, sym, Adjusted) : NULL;
> }
>
> return state;
> }
>
> const GRState*
> -BasicConstraintManager::AssumeSymLE(const GRState* state, SymbolRef sym,
> - const llvm::APSInt& V) {
> -
> - // Reject a path if the value of sym is a constant X and !(X <= V).
> +BasicConstraintManager::AssumeSymLE(const GRState *state, SymbolRef sym,
> + const llvm::APSInt &V,
> + const llvm::APSInt &Adjustment) {
> + // Reject a path if the value of sym is a constant X and !(X+Adj <= V).
> if (const llvm::APSInt* X = getSymVal(state, sym)) {
> - bool isFeasible = *X <= V;
> + bool isFeasible = (*X <= V-Adjustment);
> return isFeasible ? state : NULL;
> }
>
> // Sym is not a constant, but it is worth looking to see if V is the
> // minimum integer value.
> if (V == llvm::APSInt::getMinValue(V.getBitWidth(), V.isUnsigned())) {
> - // If we know that sym != V, then this condition is infeasible since
> - // there is no other value less than V.
> - bool isFeasible = !isNotEqual(state, sym, V);
> + llvm::APSInt Adjusted = V-Adjustment;
> +
> + // If we know that sym != V (after adjustment), then this condition
> + // is infeasible since there is no other value less than V.
> + bool isFeasible = !isNotEqual(state, sym, Adjusted);
>
> // If the path is still feasible then as a consequence we know that
> - // 'sym == V' because we cannot have 'sym < V' (no smaller values).
> + // 'sym+Adjustment == V' because there are no smaller values.
> // Add this constraint.
> - return isFeasible ? AddEQ(state, sym, V) : NULL;
> + return isFeasible ? AddEQ(state, sym, Adjusted) : NULL;
> }
>
> return state;
> @@ -213,7 +229,7 @@
> const GRState* BasicConstraintManager::AddEQ(const GRState* state, SymbolRef sym,
> const llvm::APSInt& V) {
> // Create a new state with the old binding replaced.
> - return state->set<ConstEq>(sym, &V);
> + return state->set<ConstEq>(sym, &state->getBasicVals().getValue(V));
> }
>
> const GRState* BasicConstraintManager::AddNE(const GRState* state, SymbolRef sym,
> @@ -224,7 +240,7 @@
> GRState::IntSetTy S = T ? *T : ISetFactory.GetEmptySet();
>
> // Now add V to the NE set.
> - S = ISetFactory.Add(S, &V);
> + S = ISetFactory.Add(S, &state->getBasicVals().getValue(V));
>
> // Create a new state with the old binding replaced.
> return state->set<ConstNotEq>(sym, S);
> @@ -243,7 +259,7 @@
> const ConstNotEqTy::data_type* T = state->get<ConstNotEq>(sym);
>
> // See if V is present in the NE-set.
> - return T ? T->contains(&V) : false;
> + return T ? T->contains(&state->getBasicVals().getValue(V)) : false;
> }
>
> bool BasicConstraintManager::isEqual(const GRState* state, SymbolRef sym,
>
> Modified: cfe/trunk/lib/Checker/RangeConstraintManager.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/RangeConstraintManager.cpp?rev=106339&r1=106338&r2=106339&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Checker/RangeConstraintManager.cpp (original)
> +++ cfe/trunk/lib/Checker/RangeConstraintManager.cpp Fri Jun 18 17:49:11 2010
> @@ -105,97 +105,69 @@
> return ranges.isSingleton() ? ranges.begin()->getConcreteValue() : 0;
> }
>
> - /// AddEQ - Create a new RangeSet with the additional constraint that the
> - /// value be equal to V.
> - RangeSet AddEQ(BasicValueFactory &BV, Factory &F, const llvm::APSInt &V) {
> - // Search for a range that includes 'V'. If so, return a new RangeSet
> - // representing { [V, V] }.
> - for (PrimRangeSet::iterator i = begin(), e = end(); i!=e; ++i)
> - if (i->Includes(V))
> - return RangeSet(F, V, V);
> -
> - return RangeSet(F);
> - }
> -
> - /// AddNE - Create a new RangeSet with the additional constraint that the
> - /// value be not be equal to V.
> - RangeSet AddNE(BasicValueFactory &BV, Factory &F, const llvm::APSInt &V) {
> - PrimRangeSet newRanges = ranges;
> -
> - // FIXME: We can perhaps enhance ImmutableSet to do this search for us
> - // in log(N) time using the sorted property of the internal AVL tree.
> - for (iterator i = begin(), e = end(); i != e; ++i) {
> - if (i->Includes(V)) {
> - // Remove the old range.
> - newRanges = F.Remove(newRanges, *i);
> - // Split the old range into possibly one or two ranges.
> - if (V != i->From())
> - newRanges = F.Add(newRanges, Range(i->From(), BV.Sub1(V)));
> - if (V != i->To())
> - newRanges = F.Add(newRanges, Range(BV.Add1(V), i->To()));
> - // All of the ranges are non-overlapping, so we can stop.
> +private:
> + void IntersectInRange(BasicValueFactory &BV, Factory &F,
> + const llvm::APSInt &Lower,
> + const llvm::APSInt &Upper,
> + PrimRangeSet &newRanges,
> + PrimRangeSet::iterator &i,
> + PrimRangeSet::iterator &e) const {
> + // There are six cases for each range R in the set:
> + // 1. R is entirely before the intersection range.
> + // 2. R is entirely after the intersection range.
> + // 3. R contains the entire intersection range.
> + // 4. R starts before the intersection range and ends in the middle.
> + // 5. R starts in the middle of the intersection range and ends after it.
> + // 6. R is entirely contained in the intersection range.
> + // These correspond to each of the conditions below.
> + for (/* i = begin(), e = end() */; i != e; ++i) {
> + if (i->To() < Lower) {
> + continue;
> + }
> + if (i->From() > Upper) {
> break;
> }
> - }
> -
> - return newRanges;
> - }
> -
> - /// AddNE - Create a new RangeSet with the additional constraint that the
> - /// value be less than V.
> - RangeSet AddLT(BasicValueFactory &BV, Factory &F, const llvm::APSInt &V) {
> - PrimRangeSet newRanges = F.GetEmptySet();
> -
> - for (iterator i = begin(), e = end() ; i != e ; ++i) {
> - if (i->Includes(V) && i->From() < V)
> - newRanges = F.Add(newRanges, Range(i->From(), BV.Sub1(V)));
> - else if (i->To() < V)
> - newRanges = F.Add(newRanges, *i);
> - }
> -
> - return newRanges;
> - }
> -
> - RangeSet AddLE(BasicValueFactory &BV, Factory &F, const llvm::APSInt &V) {
> - PrimRangeSet newRanges = F.GetEmptySet();
> -
> - for (iterator i = begin(), e = end(); i != e; ++i) {
> - // Strictly we should test for includes *V + 1, but no harm is
> - // done by this formulation
> - if (i->Includes(V))
> - newRanges = F.Add(newRanges, Range(i->From(), V));
> - else if (i->To() <= V)
> - newRanges = F.Add(newRanges, *i);
> - }
> -
> - return newRanges;
> - }
> -
> - RangeSet AddGT(BasicValueFactory &BV, Factory &F, const llvm::APSInt &V) {
> - PrimRangeSet newRanges = F.GetEmptySet();
>
> - for (PrimRangeSet::iterator i = begin(), e = end(); i != e; ++i) {
> - if (i->Includes(V) && i->To() > V)
> - newRanges = F.Add(newRanges, Range(BV.Add1(V), i->To()));
> - else if (i->From() > V)
> - newRanges = F.Add(newRanges, *i);
> + if (i->Includes(Lower)) {
> + if (i->Includes(Upper)) {
> + newRanges = F.Add(newRanges, Range(BV.getValue(Lower),
> + BV.getValue(Upper)));
> + break;
> + } else
> + newRanges = F.Add(newRanges, Range(BV.getValue(Lower), i->To()));
> + } else {
> + if (i->Includes(Upper)) {
> + newRanges = F.Add(newRanges, Range(i->From(), BV.getValue(Upper)));
> + break;
> + } else
> + newRanges = F.Add(newRanges, *i);
> + }
> }
> -
> - return newRanges;
> }
>
> - RangeSet AddGE(BasicValueFactory &BV, Factory &F, const llvm::APSInt &V) {
> +public:
> + // Returns a set containing the values in the receiving set, intersected with
> + // the closed range [Lower, Upper]. Unlike the Range type, this range uses
> + // modular arithmetic, corresponding to the common treatment of C integer
> + // overflow. Thus, if the Lower bound is greater than the Upper bound, the
> + // range is taken to wrap around. This is equivalent to taking the
> + // intersection with the two ranges [Min, Upper] and [Lower, Max],
> + // or, alternatively, /removing/ all integers between Upper and Lower.
> + RangeSet Intersect(BasicValueFactory &BV, Factory &F,
> + const llvm::APSInt &Lower,
> + const llvm::APSInt &Upper) const {
> PrimRangeSet newRanges = F.GetEmptySet();
>
> - for (PrimRangeSet::iterator i = begin(), e = end(); i != e; ++i) {
> - // Strictly we should test for includes *V - 1, but no harm is
> - // done by this formulation
> - if (i->Includes(V))
> - newRanges = F.Add(newRanges, Range(V, i->To()));
> - else if (i->From() >= V)
> - newRanges = F.Add(newRanges, *i);
> + PrimRangeSet::iterator i = begin(), e = end();
> + if (Lower <= Upper)
> + IntersectInRange(BV, F, Lower, Upper, newRanges, i, e);
> + else {
> + // The order of the next two statements is important!
> + // IntersectInRange() does not reset the iteration state for i and e.
> + // Therefore, the lower range most be handled first.
> + IntersectInRange(BV, F, BV.getMinValue(Upper), Upper, newRanges, i, e);
> + IntersectInRange(BV, F, Lower, BV.getMaxValue(Lower), newRanges, i, e);
> }
> -
> return newRanges;
> }
>
> @@ -237,23 +209,29 @@
> RangeConstraintManager(GRSubEngine &subengine)
> : SimpleConstraintManager(subengine) {}
>
> - const GRState* AssumeSymNE(const GRState* St, SymbolRef sym,
> - const llvm::APSInt& V);
> -
> - const GRState* AssumeSymEQ(const GRState* St, SymbolRef sym,
> - const llvm::APSInt& V);
> -
> - const GRState* AssumeSymLT(const GRState* St, SymbolRef sym,
> - const llvm::APSInt& V);
> -
> - const GRState* AssumeSymGT(const GRState* St, SymbolRef sym,
> - const llvm::APSInt& V);
> -
> - const GRState* AssumeSymGE(const GRState* St, SymbolRef sym,
> - const llvm::APSInt& V);
> -
> - const GRState* AssumeSymLE(const GRState* St, SymbolRef sym,
> - const llvm::APSInt& V);
> + const GRState* AssumeSymNE(const GRState* state, SymbolRef sym,
> + const llvm::APSInt& Int,
> + const llvm::APSInt& Adjustment);
> +
> + const GRState* AssumeSymEQ(const GRState* state, SymbolRef sym,
> + const llvm::APSInt& Int,
> + const llvm::APSInt& Adjustment);
> +
> + const GRState* AssumeSymLT(const GRState* state, SymbolRef sym,
> + const llvm::APSInt& Int,
> + const llvm::APSInt& Adjustment);
> +
> + const GRState* AssumeSymGT(const GRState* state, SymbolRef sym,
> + const llvm::APSInt& Int,
> + const llvm::APSInt& Adjustment);
> +
> + const GRState* AssumeSymGE(const GRState* state, SymbolRef sym,
> + const llvm::APSInt& Int,
> + const llvm::APSInt& Adjustment);
> +
> + const GRState* AssumeSymLE(const GRState* state, SymbolRef sym,
> + const llvm::APSInt& Int,
> + const llvm::APSInt& Adjustment);
>
> const llvm::APSInt* getSymVal(const GRState* St, SymbolRef sym) const;
>
> @@ -303,10 +281,6 @@
> return state->set<ConstraintRange>(CR);
> }
>
> -//===------------------------------------------------------------------------===
> -// AssumeSymX methods: public interface for RangeConstraintManager.
> -//===------------------------------------------------------------------------===/
> -
> RangeSet
> RangeConstraintManager::GetRange(const GRState *state, SymbolRef sym) {
> if (ConstraintRangeTy::data_type* V = state->get<ConstraintRange>(sym))
> @@ -323,20 +297,127 @@
> // AssumeSymX methods: public interface for RangeConstraintManager.
> //===------------------------------------------------------------------------===/
>
> -#define AssumeX(OP)\
> -const GRState*\
> -RangeConstraintManager::AssumeSym ## OP(const GRState* state, SymbolRef sym,\
> - const llvm::APSInt& V){\
> - const RangeSet& R = GetRange(state, sym).Add##OP(state->getBasicVals(), F, V);\
> - return !R.isEmpty() ? state->set<ConstraintRange>(sym, R) : NULL;\
> +// The syntax for ranges below is mathematical, using [x, y] for closed ranges
> +// and (x, y) for open ranges. These ranges are modular, corresponding with
> +// a common treatment of C integer overflow. This means that these methods
> +// do not have to worry about overflow; RangeSet::Intersect can handle such a
> +// "wraparound" range.
> +// As an example, the range [UINT_MAX-1, 3) contains five values: UINT_MAX-1,
> +// UINT_MAX, 0, 1, and 2.
> +
> +const GRState*
> +RangeConstraintManager::AssumeSymNE(const GRState* state, SymbolRef sym,
> + const llvm::APSInt& Int,
> + const llvm::APSInt& Adjustment) {
> + BasicValueFactory &BV = state->getBasicVals();
> +
> + llvm::APSInt Lower = Int-Adjustment;
> + llvm::APSInt Upper = Lower;
> + --Lower;
> + ++Upper;
> +
> + // [Int-Adjustment+1, Int-Adjustment-1]
> + // Notice that the lower bound is greater than the upper bound.
> + RangeSet New = GetRange(state, sym).Intersect(BV, F, Upper, Lower);
> + return New.isEmpty() ? NULL : state->set<ConstraintRange>(sym, New);
> +}
> +
> +const GRState*
> +RangeConstraintManager::AssumeSymEQ(const GRState* state, SymbolRef sym,
> + const llvm::APSInt& Int,
> + const llvm::APSInt& Adjustment) {
> + // [Int-Adjustment, Int-Adjustment]
> + BasicValueFactory &BV = state->getBasicVals();
> + llvm::APSInt AdjInt = Int-Adjustment;
> + RangeSet New = GetRange(state, sym).Intersect(BV, F, AdjInt, AdjInt);
> + return New.isEmpty() ? NULL : state->set<ConstraintRange>(sym, New);
> }
>
> -AssumeX(EQ)
> -AssumeX(NE)
> -AssumeX(LT)
> -AssumeX(GT)
> -AssumeX(LE)
> -AssumeX(GE)
> +const GRState*
> +RangeConstraintManager::AssumeSymLT(const GRState* state, SymbolRef sym,
> + const llvm::APSInt& Int,
> + const llvm::APSInt& Adjustment) {
> + BasicValueFactory &BV = state->getBasicVals();
> +
> + QualType T = state->getSymbolManager().getType(sym);
> + const llvm::APSInt &Min = BV.getMinValue(T);
> +
> + // Special case for Int == Min. This is always false.
> + if (Int == Min)
> + return NULL;
> +
> + llvm::APSInt Lower = Min-Adjustment;
> + llvm::APSInt Upper = Int-Adjustment;
> + --Upper;
> +
> + RangeSet New = GetRange(state, sym).Intersect(BV, F, Lower, Upper);
> + return New.isEmpty() ? NULL : state->set<ConstraintRange>(sym, New);
> +}
> +
> +const GRState*
> +RangeConstraintManager::AssumeSymGT(const GRState* state, SymbolRef sym,
> + const llvm::APSInt& Int,
> + const llvm::APSInt& Adjustment) {
> + BasicValueFactory &BV = state->getBasicVals();
> +
> + QualType T = state->getSymbolManager().getType(sym);
> + const llvm::APSInt &Max = BV.getMaxValue(T);
> +
> + // Special case for Int == Max. This is always false.
> + if (Int == Max)
> + return NULL;
> +
> + llvm::APSInt Lower = Int-Adjustment;
> + llvm::APSInt Upper = Max-Adjustment;
> + ++Lower;
> +
> + RangeSet New = GetRange(state, sym).Intersect(BV, F, Lower, Upper);
> + return New.isEmpty() ? NULL : state->set<ConstraintRange>(sym, New);
> +}
> +
> +const GRState*
> +RangeConstraintManager::AssumeSymGE(const GRState* state, SymbolRef sym,
> + const llvm::APSInt& Int,
> + const llvm::APSInt& Adjustment) {
> + BasicValueFactory &BV = state->getBasicVals();
> +
> + QualType T = state->getSymbolManager().getType(sym);
> + const llvm::APSInt &Min = BV.getMinValue(T);
> +
> + // Special case for Int == Min. This is always feasible.
> + if (Int == Min)
> + return state;
> +
> + const llvm::APSInt &Max = BV.getMaxValue(T);
> +
> + llvm::APSInt Lower = Int-Adjustment;
> + llvm::APSInt Upper = Max-Adjustment;
> +
> + RangeSet New = GetRange(state, sym).Intersect(BV, F, Lower, Upper);
> + return New.isEmpty() ? NULL : state->set<ConstraintRange>(sym, New);
> +}
> +
> +const GRState*
> +RangeConstraintManager::AssumeSymLE(const GRState* state, SymbolRef sym,
> + const llvm::APSInt& Int,
> + const llvm::APSInt& Adjustment) {
> + BasicValueFactory &BV = state->getBasicVals();
> +
> + QualType T = state->getSymbolManager().getType(sym);
> + const llvm::APSInt &Max = BV.getMaxValue(T);
> +
> + // Special case for Int == Max. This is always feasible.
> + if (Int == Max)
> + return state;
> +
> + const llvm::APSInt &Min = BV.getMinValue(T);
> +
> + llvm::APSInt Lower = Min-Adjustment;
> + llvm::APSInt Upper = Int-Adjustment;
> +
> + RangeSet New = GetRange(state, sym).Intersect(BV, F, Lower, Upper);
> + return New.isEmpty() ? NULL : state->set<ConstraintRange>(sym, New);
> +}
>
> //===------------------------------------------------------------------------===
> // Pretty-printing.
>
> Modified: cfe/trunk/lib/Checker/SimpleConstraintManager.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/SimpleConstraintManager.cpp?rev=106339&r1=106338&r2=106339&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Checker/SimpleConstraintManager.cpp (original)
> +++ cfe/trunk/lib/Checker/SimpleConstraintManager.cpp Fri Jun 18 17:49:11 2010
> @@ -35,12 +35,11 @@
> case BinaryOperator::Or:
> case BinaryOperator::Xor:
> return false;
> - // We don't reason yet about arithmetic constraints on symbolic values.
> + // We don't reason yet about these arithmetic constraints on
> + // symbolic values.
> case BinaryOperator::Mul:
> case BinaryOperator::Div:
> case BinaryOperator::Rem:
> - case BinaryOperator::Add:
> - case BinaryOperator::Sub:
> case BinaryOperator::Shl:
> case BinaryOperator::Shr:
> return false;
> @@ -90,12 +89,11 @@
> while (SubR) {
> // FIXME: now we only find the first symbolic region.
> if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(SubR)) {
> + const llvm::APSInt &zero = BasicVals.getZeroWithPtrWidth();
> if (Assumption)
> - return AssumeSymNE(state, SymR->getSymbol(),
> - BasicVals.getZeroWithPtrWidth());
> + return AssumeSymNE(state, SymR->getSymbol(), zero, zero);
> else
> - return AssumeSymEQ(state, SymR->getSymbol(),
> - BasicVals.getZeroWithPtrWidth());
> + return AssumeSymEQ(state, SymR->getSymbol(), zero, zero);
> }
> SubR = dyn_cast<SubRegion>(SubR->getSuperRegion());
> }
> @@ -121,11 +119,27 @@
> return SU.ProcessAssume(state, cond, assumption);
> }
>
> +static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) {
> + // FIXME: This should probably be part of BinaryOperator, since this isn't
> + // the only place it's used. (This code was copied from SimpleSValuator.cpp.)
> + switch (op) {
> + default:
> + assert(false && "Invalid opcode.");
> + case BinaryOperator::LT: return BinaryOperator::GE;
> + case BinaryOperator::GT: return BinaryOperator::LE;
> + case BinaryOperator::LE: return BinaryOperator::GT;
> + case BinaryOperator::GE: return BinaryOperator::LT;
> + case BinaryOperator::EQ: return BinaryOperator::NE;
> + case BinaryOperator::NE: return BinaryOperator::EQ;
> + }
> +}
> +
> const GRState *SimpleConstraintManager::AssumeAux(const GRState *state,
> NonLoc Cond,
> bool Assumption) {
>
> - // We cannot reason about SymIntExpr and SymSymExpr.
> + // We cannot reason about SymSymExprs,
> + // and can only reason about some SymIntExprs.
> if (!canReasonAbout(Cond)) {
> // Just return the current state indicating that the path is feasible.
> // This may be an over-approximation of what is possible.
> @@ -144,30 +158,42 @@
> SymbolRef sym = SV.getSymbol();
> QualType T = SymMgr.getType(sym);
> const llvm::APSInt &zero = BasicVals.getValue(0, T);
> -
> - return Assumption ? AssumeSymNE(state, sym, zero)
> - : AssumeSymEQ(state, sym, zero);
> + if (Assumption)
> + return AssumeSymNE(state, sym, zero, zero);
> + else
> + return AssumeSymEQ(state, sym, zero, zero);
> }
>
> case nonloc::SymExprValKind: {
> nonloc::SymExprVal V = cast<nonloc::SymExprVal>(Cond);
> - if (const SymIntExpr *SE = dyn_cast<SymIntExpr>(V.getSymbolicExpression())){
> - // FIXME: This is a hack. It silently converts the RHS integer to be
> - // of the same type as on the left side. This should be removed once
> - // we support truncation/extension of symbolic values.
> - GRStateManager &StateMgr = state->getStateManager();
> - ASTContext &Ctx = StateMgr.getContext();
> - QualType LHSType = SE->getLHS()->getType(Ctx);
> - BasicValueFactory &BasicVals = StateMgr.getBasicVals();
> - const llvm::APSInt &RHS = BasicVals.Convert(LHSType, SE->getRHS());
> - SymIntExpr SENew(SE->getLHS(), SE->getOpcode(), RHS, SE->getType(Ctx));
> -
> - return AssumeSymInt(state, Assumption, &SENew);
> - }
>
> - // For all other symbolic expressions, over-approximate and consider
> - // the constraint feasible.
> - return state;
> + // For now, we only handle expressions whose RHS is an integer.
> + // All other expressions are assumed to be feasible.
> + const SymIntExpr *SE = dyn_cast<SymIntExpr>(V.getSymbolicExpression());
> + if (!SE)
> + return state;
> +
> + GRStateManager &StateMgr = state->getStateManager();
> + ASTContext &Ctx = StateMgr.getContext();
> + BasicValueFactory &BasicVals = StateMgr.getBasicVals();
> +
> + // FIXME: This is a hack. It silently converts the RHS integer to be
> + // of the same type as on the left side. This should be removed once
> + // we support truncation/extension of symbolic values.
> + const SymExpr *LHS = SE->getLHS();
> + QualType LHSType = LHS->getType(Ctx);
> + const llvm::APSInt &RHS = BasicVals.Convert(LHSType, SE->getRHS());
> +
> + BinaryOperator::Opcode op = SE->getOpcode();
> + // FIXME: We should implicitly compare non-comparison expressions to 0.
> + if (!BinaryOperator::isComparisonOp(op))
> + return state;
> +
> + // From here on out, op is the real comparison we'll be testing.
> + if (!Assumption)
> + op = NegateComparison(op);
> +
> + return AssumeSymRel(state, LHS, op, RHS);
> }
>
> case nonloc::ConcreteIntKind: {
> @@ -182,43 +208,76 @@
> } // end switch
> }
>
> -const GRState *SimpleConstraintManager::AssumeSymInt(const GRState *state,
> - bool Assumption,
> - const SymIntExpr *SE) {
> -
> -
> - // Here we assume that LHS is a symbol. This is consistent with the
> - // rest of the constraint manager logic.
> - SymbolRef Sym = cast<SymbolData>(SE->getLHS());
> - const llvm::APSInt &Int = SE->getRHS();
> +const GRState *SimpleConstraintManager::AssumeSymRel(const GRState *state,
> + const SymExpr *LHS,
> + BinaryOperator::Opcode op,
> + const llvm::APSInt& Int) {
> + assert(BinaryOperator::isComparisonOp(op) &&
> + "Non-comparison ops should be rewritten as comparisons to zero.");
> +
> + // We only handle simple comparisons of the form "$sym == constant"
> + // or "($sym+constant1) == constant2".
> + // The adjustment is "constant1" in the above expression. It's used to
> + // "slide" the solution range around for modular arithmetic. For example,
> + // x < 4 has the solution [0, 3]. x+2 < 4 has the solution [0-2, 3-2], which
> + // in modular arithmetic is [0, 1] U [UINT_MAX-1, UINT_MAX]. It's up to
> + // the subclasses of SimpleConstraintManager to handle the adjustment.
> + llvm::APSInt Adjustment(Int.getBitWidth(), Int.isUnsigned());
> +
> + // First check if the LHS is a simple symbol reference.
> + SymbolRef Sym = dyn_cast<SymbolData>(LHS);
> + if (!Sym) {
> + // Next, see if it's a "($sym+constant1)" expression.
> + const SymIntExpr *SE = dyn_cast<SymIntExpr>(LHS);
> +
> + // We don't handle "($sym1+$sym2)".
> + // Give up and assume the constraint is feasible.
> + if (!SE)
> + return state;
> +
> + // We don't handle "(<expr>+constant1)".
> + // Give up and assume the constraint is feasible.
> + Sym = dyn_cast<SymbolData>(SE->getLHS());
> + if (!Sym)
> + return state;
> +
> + // Get the constant out of the expression "($sym+constant1)".
> + switch (SE->getOpcode()) {
> + case BinaryOperator::Add:
> + Adjustment = SE->getRHS();
> + break;
> + case BinaryOperator::Sub:
> + Adjustment = -SE->getRHS();
> + break;
> + default:
> + // We don't handle non-additive operators.
> + // Give up and assume the constraint is feasible.
> + return state;
> + }
> + }
>
> - switch (SE->getOpcode()) {
> + switch (op) {
> default:
> // No logic yet for other operators. Assume the constraint is feasible.
> return state;
>
> case BinaryOperator::EQ:
> - return Assumption ? AssumeSymEQ(state, Sym, Int)
> - : AssumeSymNE(state, Sym, Int);
> + return AssumeSymEQ(state, Sym, Int, Adjustment);
>
> case BinaryOperator::NE:
> - return Assumption ? AssumeSymNE(state, Sym, Int)
> - : AssumeSymEQ(state, Sym, Int);
> + return AssumeSymNE(state, Sym, Int, Adjustment);
> +
> case BinaryOperator::GT:
> - return Assumption ? AssumeSymGT(state, Sym, Int)
> - : AssumeSymLE(state, Sym, Int);
> + return AssumeSymGT(state, Sym, Int, Adjustment);
>
> case BinaryOperator::GE:
> - return Assumption ? AssumeSymGE(state, Sym, Int)
> - : AssumeSymLT(state, Sym, Int);
> + return AssumeSymGE(state, Sym, Int, Adjustment);
>
> case BinaryOperator::LT:
> - return Assumption ? AssumeSymLT(state, Sym, Int)
> - : AssumeSymGE(state, Sym, Int);
> + return AssumeSymLT(state, Sym, Int, Adjustment);
>
> case BinaryOperator::LE:
> - return Assumption ? AssumeSymLE(state, Sym, Int)
> - : AssumeSymGT(state, Sym, Int);
> + return AssumeSymLE(state, Sym, Int, Adjustment);
> } // end switch
> }
>
>
> Modified: cfe/trunk/lib/Checker/SimpleConstraintManager.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/SimpleConstraintManager.h?rev=106339&r1=106338&r2=106339&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Checker/SimpleConstraintManager.h (original)
> +++ cfe/trunk/lib/Checker/SimpleConstraintManager.h Fri Jun 18 17:49:11 2010
> @@ -38,8 +38,10 @@
>
> const GRState *Assume(const GRState *state, NonLoc Cond, bool Assumption);
>
> - const GRState *AssumeSymInt(const GRState *state, bool Assumption,
> - const SymIntExpr *SE);
> + const GRState *AssumeSymRel(const GRState *state,
> + const SymExpr *LHS,
> + BinaryOperator::Opcode op,
> + const llvm::APSInt& Int);
>
> const GRState *AssumeInBound(const GRState *state, DefinedSVal Idx,
> DefinedSVal UpperBound,
> @@ -51,23 +53,31 @@
> // Interface that subclasses must implement.
> //===------------------------------------------------------------------===//
>
> + // Each of these is of the form "$sym+Adj <> V", where "<>" is the comparison
> + // operation for the method being invoked.
> virtual const GRState *AssumeSymNE(const GRState *state, SymbolRef sym,
> - const llvm::APSInt& V) = 0;
> + const llvm::APSInt& V,
> + const llvm::APSInt& Adjustment) = 0;
>
> virtual const GRState *AssumeSymEQ(const GRState *state, SymbolRef sym,
> - const llvm::APSInt& V) = 0;
> + const llvm::APSInt& V,
> + const llvm::APSInt& Adjustment) = 0;
>
> virtual const GRState *AssumeSymLT(const GRState *state, SymbolRef sym,
> - const llvm::APSInt& V) = 0;
> + const llvm::APSInt& V,
> + const llvm::APSInt& Adjustment) = 0;
>
> virtual const GRState *AssumeSymGT(const GRState *state, SymbolRef sym,
> - const llvm::APSInt& V) = 0;
> + const llvm::APSInt& V,
> + const llvm::APSInt& Adjustment) = 0;
>
> virtual const GRState *AssumeSymLE(const GRState *state, SymbolRef sym,
> - const llvm::APSInt& V) = 0;
> + const llvm::APSInt& V,
> + const llvm::APSInt& Adjustment) = 0;
>
> virtual const GRState *AssumeSymGE(const GRState *state, SymbolRef sym,
> - const llvm::APSInt& V) = 0;
> + const llvm::APSInt& V,
> + const llvm::APSInt& Adjustment) = 0;
>
> //===------------------------------------------------------------------===//
> // Internal implementation.
>
> Modified: cfe/trunk/lib/Checker/SimpleSValuator.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/SimpleSValuator.cpp?rev=106339&r1=106338&r2=106339&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Checker/SimpleSValuator.cpp (original)
> +++ cfe/trunk/lib/Checker/SimpleSValuator.cpp Fri Jun 18 17:49:11 2010
> @@ -261,63 +261,88 @@
> }
> }
> case nonloc::SymExprValKind: {
> - // Logical not?
> - if (!(op == BinaryOperator::EQ && rhs.isZeroConstant()))
> + nonloc::SymExprVal *selhs = cast<nonloc::SymExprVal>(&lhs);
> +
> + // Only handle LHS of the form "$sym op constant", at least for now.
> + const SymIntExpr *symIntExpr =
> + dyn_cast<SymIntExpr>(selhs->getSymbolicExpression());
> +
> + if (!symIntExpr)
> return UnknownVal();
>
> - const SymExpr *symExpr =
> - cast<nonloc::SymExprVal>(lhs).getSymbolicExpression();
> + // Is this a logical not? (!x is represented as x == 0.)
> + if (op == BinaryOperator::EQ && rhs.isZeroConstant()) {
> + // We know how to negate certain expressions. Simplify them here.
>
> - // Only handle ($sym op constant) for now.
> - if (const SymIntExpr *symIntExpr = dyn_cast<SymIntExpr>(symExpr)) {
> BinaryOperator::Opcode opc = symIntExpr->getOpcode();
> switch (opc) {
> - case BinaryOperator::LAnd:
> - case BinaryOperator::LOr:
> - assert(false && "Logical operators handled by branching logic.");
> - return UnknownVal();
> - case BinaryOperator::Assign:
> - case BinaryOperator::MulAssign:
> - case BinaryOperator::DivAssign:
> - case BinaryOperator::RemAssign:
> - case BinaryOperator::AddAssign:
> - case BinaryOperator::SubAssign:
> - case BinaryOperator::ShlAssign:
> - case BinaryOperator::ShrAssign:
> - case BinaryOperator::AndAssign:
> - case BinaryOperator::XorAssign:
> - case BinaryOperator::OrAssign:
> - case BinaryOperator::Comma:
> - assert(false && "'=' and ',' operators handled by GRExprEngine.");
> - return UnknownVal();
> - case BinaryOperator::PtrMemD:
> - case BinaryOperator::PtrMemI:
> - assert(false && "Pointer arithmetic not handled here.");
> - return UnknownVal();
> - case BinaryOperator::Mul:
> - case BinaryOperator::Div:
> - case BinaryOperator::Rem:
> - case BinaryOperator::Add:
> - case BinaryOperator::Sub:
> - case BinaryOperator::Shl:
> - case BinaryOperator::Shr:
> - case BinaryOperator::And:
> - case BinaryOperator::Xor:
> - case BinaryOperator::Or:
> - // Not handled yet.
> - return UnknownVal();
> - case BinaryOperator::LT:
> - case BinaryOperator::GT:
> - case BinaryOperator::LE:
> - case BinaryOperator::GE:
> - case BinaryOperator::EQ:
> - case BinaryOperator::NE:
> - opc = NegateComparison(opc);
> - assert(symIntExpr->getType(ValMgr.getContext()) == resultTy);
> - return ValMgr.makeNonLoc(symIntExpr->getLHS(), opc,
> - symIntExpr->getRHS(), resultTy);
> + default:
> + // We don't know how to negate this operation.
> + // Just handle it as if it were a normal comparison to 0.
> + break;
> + case BinaryOperator::LAnd:
> + case BinaryOperator::LOr:
> + assert(false && "Logical operators handled by branching logic.");
> + return UnknownVal();
> + case BinaryOperator::Assign:
> + case BinaryOperator::MulAssign:
> + case BinaryOperator::DivAssign:
> + case BinaryOperator::RemAssign:
> + case BinaryOperator::AddAssign:
> + case BinaryOperator::SubAssign:
> + case BinaryOperator::ShlAssign:
> + case BinaryOperator::ShrAssign:
> + case BinaryOperator::AndAssign:
> + case BinaryOperator::XorAssign:
> + case BinaryOperator::OrAssign:
> + case BinaryOperator::Comma:
> + assert(false && "'=' and ',' operators handled by GRExprEngine.");
> + return UnknownVal();
> + case BinaryOperator::PtrMemD:
> + case BinaryOperator::PtrMemI:
> + assert(false && "Pointer arithmetic not handled here.");
> + return UnknownVal();
> + case BinaryOperator::LT:
> + case BinaryOperator::GT:
> + case BinaryOperator::LE:
> + case BinaryOperator::GE:
> + case BinaryOperator::EQ:
> + case BinaryOperator::NE:
> + // Negate the comparison and make a value.
> + opc = NegateComparison(opc);
> + assert(symIntExpr->getType(ValMgr.getContext()) == resultTy);
> + return ValMgr.makeNonLoc(symIntExpr->getLHS(), opc,
> + symIntExpr->getRHS(), resultTy);
> + }
> + }
> +
> + // For now, only handle expressions whose RHS is a constant.
> + const nonloc::ConcreteInt *rhsInt = dyn_cast<nonloc::ConcreteInt>(&rhs);
> + if (!rhsInt)
> + return UnknownVal();
> +
> + // If both the LHS and the current expression are additive,
> + // fold their constants.
> + if (BinaryOperator::isAdditiveOp(op)) {
> + BinaryOperator::Opcode lop = symIntExpr->getOpcode();
> + if (BinaryOperator::isAdditiveOp(lop)) {
> + BasicValueFactory &BVF = ValMgr.getBasicValueFactory();
> + const llvm::APSInt *newRHS;
> + if (lop == op)
> + newRHS = BVF.EvaluateAPSInt(BinaryOperator::Add,
> + symIntExpr->getRHS(),
> + rhsInt->getValue());
> + else
> + newRHS = BVF.EvaluateAPSInt(BinaryOperator::Sub,
> + symIntExpr->getRHS(),
> + rhsInt->getValue());
> + return ValMgr.makeNonLoc(symIntExpr->getLHS(), lop, *newRHS,
> + resultTy);
> }
> }
> +
> + // Otherwise, make a SymExprVal out of the expression.
> + return ValMgr.makeNonLoc(symIntExpr, op, rhsInt->getValue(), resultTy);
> }
> case nonloc::ConcreteIntKind: {
> if (isa<nonloc::ConcreteInt>(rhs)) {
>
> Added: cfe/trunk/test/Analysis/additive-folding-range-constraints.c
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/additive-folding-range-constraints.c?rev=106339&view=auto
> ==============================================================================
> --- cfe/trunk/test/Analysis/additive-folding-range-constraints.c (added)
> +++ cfe/trunk/test/Analysis/additive-folding-range-constraints.c Fri Jun 18 17:49:11 2010
> @@ -0,0 +1,99 @@
> +// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-experimental-checks -verify -analyzer-constraints=range %s
> +#include <limits.h>
> +
> +// These are used to trigger warnings.
> +typedef typeof(sizeof(int)) size_t;
> +void *malloc(size_t);
> +void free(void *);
> +#define NULL ((void*)0)
> +
> +// Each of these adjusted ranges has an adjustment small enough to split the
> +// solution range across an overflow boundary (Min for <, Max for >).
> +// This corresponds to one set of branches in RangeConstraintManager.
> +void smallAdjustmentGT (unsigned a) {
> + char* b = NULL;
> + if (a+2 > 1)
> + b = malloc(1);
> + if (a == UINT_MAX-1 || a == UINT_MAX)
> + return; // no-warning
> + else if (a < UINT_MAX-1)
> + free(b);
> + return; // no-warning
> +}
> +
> +void smallAdjustmentGE (unsigned a) {
> + char* b = NULL;
> + if (a+2 >= 1)
> + b = malloc(1);
> + if (a == UINT_MAX-1)
> + return; // no-warning
> + else if (a < UINT_MAX-1 || a == UINT_MAX)
> + free(b);
> + return; // no-warning
> +}
> +
> +void smallAdjustmentLT (unsigned a) {
> + char* b = NULL;
> + if (a+1 < 2)
> + b = malloc(1);
> + if (a == 0 || a == UINT_MAX)
> + free(b);
> + return; // no-warning
> +}
> +
> +void smallAdjustmentLE (unsigned a) {
> + char* b = NULL;
> + if (a+1 <= 2)
> + b = malloc(1);
> + if (a == 0 || a == 1 || a == UINT_MAX)
> + free(b);
> + return; // no-warning
> +}
> +
> +
> +// Each of these adjusted ranges has an adjustment large enough to push the
> +// comparison value over an overflow boundary (Min for <, Max for >).
> +// This corresponds to one set of branches in RangeConstraintManager.
> +void largeAdjustmentGT (unsigned a) {
> + char* b = NULL;
> + if (a-2 > UINT_MAX-1)
> + b = malloc(1);
> + if (a == 1 || a == 0)
> + free(b);
> + else if (a > 1)
> + free(b);
> + return; // no-warning
> +}
> +
> +void largeAdjustmentGE (unsigned a) {
> + char* b = NULL;
> + if (a-2 >= UINT_MAX-1)
> + b = malloc(1);
> + if (a > 1)
> + return; // no-warning
> + else if (a == 1 || a == 0)
> + free(b);
> + return; // no-warning
> +}
> +
> +void largeAdjustmentLT (unsigned a) {
> + char* b = NULL;
> + if (a+2 < 1)
> + b = malloc(1);
> + if (a == UINT_MAX-1 || a == UINT_MAX)
> + free(b);
> + else if (a < UINT_MAX-1)
> + return; // no-warning
> + return; // no-warning
> +}
> +
> +void largeAdjustmentLE (unsigned a) {
> + char* b = NULL;
> + if (a+2 <= 1)
> + b = malloc(1);
> + if (a < UINT_MAX-1)
> + return; // no-warning
> + else if (a == UINT_MAX-1 || a == UINT_MAX)
> + free(b);
> + return; // no-warning
> +}
>
> Added: cfe/trunk/test/Analysis/additive-folding.c
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/additive-folding.c?rev=106339&view=auto
> ==============================================================================
> --- cfe/trunk/test/Analysis/additive-folding.c (added)
> +++ cfe/trunk/test/Analysis/additive-folding.c Fri Jun 18 17:49:11 2010
> @@ -0,0 +1,163 @@
> +// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-experimental-checks -verify -analyzer-constraints=basic %s
> +// RUN: %clang_cc1 -analyze -analyzer-check-objc-mem -analyzer-experimental-checks -verify -analyzer-constraints=range %s
> +#include <limits.h>
> +
> +// These are used to trigger warnings.
> +typedef typeof(sizeof(int)) size_t;
> +void *malloc(size_t);
> +void free(void *);
> +#define NULL ((void*)0)
> +
> +//---------------
> +// Plus/minus
> +//---------------
> +
> +void separateExpressions (int a) {
> + int b = a + 1;
> + --b;
> +
> + char* buf = malloc(1);
> + if (a != 0 && b == 0)
> + return; // no-warning
> + free(buf);
> +}
> +
> +void oneLongExpression (int a) {
> + // Expression canonicalization should still allow this to work, even though
> + // the first term is on the left.
> + int b = 15 + a + 15 - 10 - 20;
> +
> + char* buf = malloc(1);
> + if (a != 0 && b == 0)
> + return; // no-warning
> + free(buf);
> +}
> +
> +//---------------
> +// Comparisons
> +//---------------
> +
> +// Equality and inequality only
> +void eq_ne (unsigned a) {
> + char* b = NULL;
> + if (a == UINT_MAX)
> + b = malloc(1);
> + if (a+1 != 0)
> + return; // no-warning
> + if (a-1 != UINT_MAX-1)
> + return; // no-warning
> + free(b);
> +}
> +
> +void ne_eq (unsigned a) {
> + char* b = NULL;
> + if (a != UINT_MAX)
> + b = malloc(1);
> + if (a+1 == 0)
> + return; // no-warning
> + if (a-1 == UINT_MAX-1)
> + return; // no-warning
> + free(b);
> +}
> +
> +
> +// Simple order comparisons with no adjustment
> +void baselineGT (unsigned a) {
> + char* b = NULL;
> + if (a > 0)
> + b = malloc(1);
> + if (a == 0)
> + return; // no-warning
> + free(b);
> +}
> +
> +void baselineGE (unsigned a) {
> + char* b = NULL;
> + if (a >= UINT_MAX)
> + b = malloc(1);
> + if (a == UINT_MAX)
> + free(b);
> + return; // no-warning
> +}
> +
> +void baselineLT (unsigned a) {
> + char* b = NULL;
> + if (a < UINT_MAX)
> + b = malloc(1);
> + if (a == UINT_MAX)
> + return; // no-warning
> + free(b);
> +}
> +
> +void baselineLE (unsigned a) {
> + char* b = NULL;
> + if (a <= 0)
> + b = malloc(1);
> + if (a == 0)
> + free(b);
> + return; // no-warning
> +}
> +
> +
> +// Adjustment gives each of these an extra solution!
> +void adjustedGT (unsigned a) {
> + char* b = NULL;
> + if (a-1 > UINT_MAX-1)
> + b = malloc(1);
> + return; // expected-warning{{leak}}
> +}
> +
> +void adjustedGE (unsigned a) {
> + char* b = NULL;
> + if (a-1 >= UINT_MAX-1)
> + b = malloc(1);
> + if (a == UINT_MAX)
> + free(b);
> + return; // expected-warning{{leak}}
> +}
> +
> +void adjustedLT (unsigned a) {
> + char* b = NULL;
> + if (a+1 < 1)
> + b = malloc(1);
> + return; // expected-warning{{leak}}
> +}
> +
> +void adjustedLE (unsigned a) {
> + char* b = NULL;
> + if (a+1 <= 1)
> + b = malloc(1);
> + if (a == 0)
> + free(b);
> + return; // expected-warning{{leak}}
> +}
> +
> +
> +// Tautologies
> +void tautologyGT (unsigned a) {
> + char* b = malloc(1);
> + if (a > UINT_MAX)
> + return; // no-warning
> + free(b);
> +}
> +
> +void tautologyGE (unsigned a) {
> + char* b = malloc(1);
> + if (a >= 0)
> + free(b);
> + return; // no-warning
> +}
> +
> +void tautologyLT (unsigned a) {
> + char* b = malloc(1);
> + if (a < 0)
> + return; // no-warning
> + free(b);
> +}
> +
> +void tautologyLE (unsigned a) {
> + char* b = malloc(1);
> + if (a <= UINT_MAX)
> + free(b);
> + return; // no-warning
> +}
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list