[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