diff --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp --- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp @@ -1327,6 +1327,8 @@ // Of course, we should take the constraint directly // associated with this symbol into consideration. getConstraint(State, Sym), + // Use inverted ranges from DisequalityMap. + getInvertedRangeFromDisequalityMap(State, Sym), // Apart from the Sym itself, we can infer quite a lot if // we look into subexpressions of Sym. Visit(Sym)); @@ -1490,6 +1492,39 @@ return RangeFactory.deletePoint(Domain, IntType.getZeroValue()); } + Optional getInvertedRangeFromDisequalityMap(ProgramStateRef State, + SymbolRef Sym) { + QualType T = Sym->getType(); + // We only support integral types. + if (!T->isIntegralOrEnumerationType()) + return llvm::None; + + EquivalenceClass EC = EquivalenceClass::find(State, Sym); + const ClassSet *CS = State->get(EC); + + if (!CS) + return llvm::None; + + bool IsFirst = true; + RangeSet RS = RangeFactory.getEmptySet(); + for (EquivalenceClass EC : *CS) { + if (const RangeSet *RSPtr = getConstraint(State, EC)) { + if (IsFirst) { + IsFirst = false; + RS = *RSPtr; + } else + RS = RangeFactory.unite(RS, *RSPtr); + } + } + + if (IsFirst) + return llvm::None; + + RS = RangeFactory.castTo(RS, T); + RS = RangeFactory.invert(RS); + return RS; + } + template Optional getRangeForNegatedExpr(ProduceNegatedSymFunc F, QualType T) { @@ -3217,8 +3252,12 @@ void RangeConstraintManager::printValue(raw_ostream &Out, ProgramStateRef State, SymbolRef Sym) { const RangeSet RS = getRange(State, Sym); - Out << RS.getBitWidth() << (RS.isUnsigned() ? "u:" : "s:"); - RS.dump(Out); + if (RS.isEmpty()) + Out << "{ empty }"; + else { + Out << RS.getBitWidth() << (RS.isUnsigned() ? "u:" : "s:"); + RS.dump(Out); + } } static std::string toString(const SymbolRef &Sym) { diff --git a/clang/test/Analysis/range-inferring-from-disequality-map.cpp b/clang/test/Analysis/range-inferring-from-disequality-map.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Analysis/range-inferring-from-disequality-map.cpp @@ -0,0 +1,57 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=debug.ExprInspection -verify %s + +template +void clang_analyzer_value(T x); + +void test1(int x, int tmp) { + if(tmp != 0) + if(x != tmp) + clang_analyzer_value(x); // expected-warning {{32s:{ [0, 0] }}} + // TODO: TODO: Keep x range correct even if associated disequalities are + // already dead. + (void)tmp; // Keep alive. +} + +void test2(int x, int tmp) { + if(x != tmp) + if(tmp < 0) + clang_analyzer_value(x); // expected-warning {{32s:{ [0, 2147483647] }}} + // TODO: TODO: Keep x range correct even if associated disequalities are + // already dead. + (void)tmp; // Keep alive. +} + +void test3(int x, int tmp) { + if(x != tmp) + if(tmp > 42 && tmp < 87) + clang_analyzer_value(x); // expected-warning {{32s:{ [-2147483648, 42], [87, 2147483647] }}} + // TODO: TODO: Keep x range correct even if associated disequalities are + // already dead. + (void)tmp; // Keep alive. +} + +void test4(int x, int tmp1, int tmp2) { + if(x != tmp1) { + if (tmp1 < 0 && tmp2 > 0) { + clang_analyzer_value(x); // expected-warning {{32s:{ [0, 2147483647] }}} + if(x != tmp2) + clang_analyzer_value(x); // expected-warning {{32s:{ [0, 0] }}} + } + } + // TODO: TODO: Keep x range correct even if associated disequalities are + // already dead. + (void)tmp1; // Keep alive. + (void)tmp2; // Keep alive. +} + +void test5(int x, int tmp1, int tmp2) { + if (tmp1 < 42 && tmp2 >= 42) + if(x != tmp1 && x != tmp2) + // TODO: This condition should be infeasible. + // Thus, the branch should be unreachable. + clang_analyzer_value(x); // expected-warning {{{ empty }}} + // TODO: TODO: Keep x range correct even if associated disequalities are + // already dead. + (void)tmp1; // Keep alive. + (void)tmp2; // Keep alive. +}