Index: lib/StaticAnalyzer/Core/RangeConstraintManager.cpp =================================================================== --- lib/StaticAnalyzer/Core/RangeConstraintManager.cpp +++ lib/StaticAnalyzer/Core/RangeConstraintManager.cpp @@ -460,6 +460,44 @@ return Changed ? State->set(CR) : State; } +/// \brief Apply implicit constraints for bitwise OR- and AND-. +/// For unsigned types, bitwise OR with a constant always returns +/// a value greater-or-equal than the constant, and bitwise AND +/// returns a value less-or-equal then the constant. +/// +/// Pattern matches the expression \p Sym against those rule, +/// and applies the required constraints. +static RangeSet applyBitwiseConstraints( + BasicValueFactory &BV, + RangeSet::Factory &F, + QualType T, + RangeSet Result, + SymbolRef Sym) { + + if (const SymIntExpr *SIE = dyn_cast(Sym)) { + + // Only apply the rule to unsigned types, otherwise sign + // may change and ordering will be violated. + if (!SIE->getLHS()->getType()->isUnsignedIntegerType()) + return Result; + + switch (SIE->getOpcode()) { + case BO_Or: + + // result >= constant + return Result.Intersect(BV, F, SIE->getRHS(), BV.getMaxValue(T)); + case BO_And: + + // result <= constant + return Result.Intersect(BV, F, BV.getMinValue(T), SIE->getRHS()); + default: + break; + } + } + return Result; + +} + RangeSet RangeConstraintManager::getRange(ProgramStateRef State, SymbolRef Sym) { if (ConstraintRangeTy::data_type *V = State->get(Sym)) @@ -479,6 +517,7 @@ --IntType.getZeroValue()); } + Result = applyBitwiseConstraints(BV, F, T, Result, Sym); return Result; } Index: test/Analysis/constant-folding.c =================================================================== --- test/Analysis/constant-folding.c +++ test/Analysis/constant-folding.c @@ -76,3 +76,23 @@ clang_analyzer_eval(b >= a); // expected-warning{{TRUE}} clang_analyzer_eval(a != b); // expected-warning{{TRUE}} } + +void testBitwiseRules(unsigned int a, int b) { + clang_analyzer_eval((a | 1) > 0); // expected-warning{{TRUE}} + clang_analyzer_eval((1 | a) > 0); // expected-warning{{TRUE}} + clang_analyzer_eval((a & 1) < 2); // expected-warning{{TRUE}} + clang_analyzer_eval((1 & a) < 2); // expected-warning{{TRUE}} + + unsigned int c = a; + c |= 1; + clang_analyzer_eval((c | 0) == 0); // expected-warning{{FALSE}} + + // Rules don't apply to signed typed, as the values might be negative. + clang_analyzer_eval((b | 1) > 0); // expected-warning{{UNKNOWN}} + clang_analyzer_eval((b | 1) == 0); // expected-warning{{UNKNOWN}} + + // Check that dynamically computed constants also work. + int constant = 1 << 3; + unsigned int d = a | constant; + clang_analyzer_eval(constant > 0); // expected-warning{{TRUE}} +}