Index: lib/StaticAnalyzer/Core/RangeConstraintManager.cpp =================================================================== --- lib/StaticAnalyzer/Core/RangeConstraintManager.cpp +++ lib/StaticAnalyzer/Core/RangeConstraintManager.cpp @@ -256,6 +256,29 @@ return newRanges; } + // Turn all [A, B] ranges to [-B, -A]. Turn minimal signed value to maximal + // signed value and vice versa. + RangeSet Negate(BasicValueFactory &BV, Factory &F) const { + PrimRangeSet newRanges = F.getEmptySet(); + + for (iterator i = begin(), e = end(); i != e; ++i) { + const llvm::APSInt &from = i->From(), &to = i->To(); + const llvm::APSInt &newFrom = (to.isMinSignedValue() ? + BV.getMaxValue(to) : + (to.isMaxSignedValue() ? + BV.getMinValue(to) : + BV.getValue(- to))); + const llvm::APSInt &newTo = (from.isMinSignedValue() ? + BV.getMaxValue(from) : + (from.isMaxSignedValue() ? + BV.getMinValue(from) : + BV.getValue(- from))); + newRanges = F.add(newRanges, Range(newFrom, newTo)); + } + + return newRanges; + } + void print(raw_ostream &os) const { bool isFirst = true; os << "{ "; @@ -515,11 +538,37 @@ if (ConstraintRangeTy::data_type *V = State->get(Sym)) return *V; - // Lazily generate a new RangeSet representing all possible values for the - // given symbol type. + // If Sym is a difference of symbols A - B, then maybe we have range set + // stored for B - A. BasicValueFactory &BV = getBasicVals(); QualType T = Sym->getType(); + if (const SymSymExpr *SSE = dyn_cast(Sym)) { + // FIXME: Once SValBuilder supports unary minus, we should use SValBuilder + // to obtain the negated symbolic expression instead of constructing + // the symbol manually. This will allow us to support finding ranges + // of not only negated SymSymExpr-type expressions, but also of + // other, simpler expressions which we currently do not know how to + // negate. + if (SSE->getOpcode() == BO_Sub) { + SymbolManager &SymMgr = State->getSymbolManager(); + SymbolRef negSym = SymMgr.getSymSymExpr(SSE->getRHS(), BO_Sub, + SSE->getLHS(), T); + if (ConstraintRangeTy::data_type *negV = + State->get(negSym)) { + // Unsigned range set cannot be negated, unless it is [0, 0]. + if ((negV->getConcreteValue() && + (*negV->getConcreteValue() == 0)) || + T->isSignedIntegerOrEnumerationType()) { + return negV->Negate(BV, F); + } + } + } + } + + // Lazily generate a new RangeSet representing all possible values for the + // given symbol type. + RangeSet Result(F, BV.getMinValue(T), BV.getMaxValue(T)); // References are known to be non-zero. Index: test/Analysis/constraint_manager_negate_difference.c =================================================================== --- /dev/null +++ test/Analysis/constraint_manager_negate_difference.c @@ -0,0 +1,64 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=debug.ExprInspection,core.builtin -analyzer-config aggressive-relational-comparison-simplification=true -verify %s + +void clang_analyzer_eval(int); + +void exit(int); + +#define UINT_MAX (~0U) +#define INT_MAX (UINT_MAX & (UINT_MAX >> 1)) + +void assert_in_range(int x) { + // Assert that no overflows occur in this test file. + // Assuming that concrete integers are also within that range. + if (x > ((int)INT_MAX / 4)) + exit(1); + if (x < -(((int)INT_MAX) / 4)) + exit(1); +} + +void assert_in_range_2(int m, int n) { + assert_in_range(m); + assert_in_range(n); +} + +void equal(int m, int n) { + assert_in_range_2(m, n); + if (m != n) + return; + clang_analyzer_eval(n == m); // expected-warning{{TRUE}} +} + +void non_equal(int m, int n) { + assert_in_range_2(m, n); + if (m == n) + return; + clang_analyzer_eval(n != m); // expected-warning{{TRUE}} +} + +void less_or_equal(int m, int n) { + assert_in_range_2(m, n); + if (m < n) + return; + clang_analyzer_eval(n <= m); // expected-warning{{TRUE}} +} + +void less(int m, int n) { + assert_in_range_2(m, n); + if (m <= n) + return; + clang_analyzer_eval(n < m); // expected-warning{{TRUE}} +} + +void greater_or_equal(int m, int n) { + assert_in_range_2(m, n); + if (m > n) + return; + clang_analyzer_eval(n >= m); // expected-warning{{TRUE}} +} + +void greater(int m, int n) { + assert_in_range_2(m, n); + if (m >= n) + return; + clang_analyzer_eval(n > m); // expected-warning{{TRUE}} +} Index: test/Analysis/ptr-arith.c =================================================================== --- test/Analysis/ptr-arith.c +++ test/Analysis/ptr-arith.c @@ -265,49 +265,26 @@ clang_analyzer_eval((rhs - lhs) > 0); // expected-warning{{TRUE}} } -//------------------------------- -// False positives -//------------------------------- - void zero_implies_reversed_equal(int *lhs, int *rhs) { clang_analyzer_eval((rhs - lhs) == 0); // expected-warning{{UNKNOWN}} if ((rhs - lhs) == 0) { -#ifdef ANALYZER_CM_Z3 clang_analyzer_eval(rhs != lhs); // expected-warning{{FALSE}} clang_analyzer_eval(rhs == lhs); // expected-warning{{TRUE}} -#else - clang_analyzer_eval(rhs != lhs); // expected-warning{{UNKNOWN}} - clang_analyzer_eval(rhs == lhs); // expected-warning{{UNKNOWN}} -#endif return; } clang_analyzer_eval((rhs - lhs) == 0); // expected-warning{{FALSE}} -#ifdef ANALYZER_CM_Z3 clang_analyzer_eval(rhs == lhs); // expected-warning{{FALSE}} clang_analyzer_eval(rhs != lhs); // expected-warning{{TRUE}} -#else - clang_analyzer_eval(rhs == lhs); // expected-warning{{UNKNOWN}} - clang_analyzer_eval(rhs != lhs); // expected-warning{{UNKNOWN}} -#endif } void canonical_equal(int *lhs, int *rhs) { clang_analyzer_eval(lhs == rhs); // expected-warning{{UNKNOWN}} if (lhs == rhs) { -#ifdef ANALYZER_CM_Z3 clang_analyzer_eval(rhs == lhs); // expected-warning{{TRUE}} -#else - clang_analyzer_eval(rhs == lhs); // expected-warning{{UNKNOWN}} -#endif return; } clang_analyzer_eval(lhs == rhs); // expected-warning{{FALSE}} - -#ifdef ANALYZER_CM_Z3 clang_analyzer_eval(rhs == lhs); // expected-warning{{FALSE}} -#else - clang_analyzer_eval(rhs == lhs); // expected-warning{{UNKNOWN}} -#endif } void compare_element_region_and_base(int *p) {