r317820 - [analyzer] assume bitwise arithmetic axioms
George Karpenkov via cfe-commits
cfe-commits at lists.llvm.org
Thu Nov 9 11:06:22 PST 2017
Author: george.karpenkov
Date: Thu Nov 9 11:06:22 2017
New Revision: 317820
URL: http://llvm.org/viewvc/llvm-project?rev=317820&view=rev
Log:
[analyzer] assume bitwise arithmetic axioms
Patches the solver to assume that bitwise OR of an unsigned value with a
constant always produces a value larger-or-equal than the constant, and
bitwise AND with a constant always produces a value less-or-equal than
the constant.
This patch is especially useful in the context of using bitwise
arithmetic for error code encoding: the analyzer would be able to state
that the error code produced using a bitwise OR is non-zero.
Differential Revision: https://reviews.llvm.org/D39707
Modified:
cfe/trunk/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
cfe/trunk/test/Analysis/constant-folding.c
Modified: cfe/trunk/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp?rev=317820&r1=317819&r2=317820&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp Thu Nov 9 11:06:22 2017
@@ -460,6 +460,53 @@ RangeConstraintManager::removeDeadBindin
return Changed ? State->set<ConstraintRange>(CR) : State;
}
+/// Return a range set subtracting zero from \p Domain.
+static RangeSet assumeNonZero(
+ BasicValueFactory &BV,
+ RangeSet::Factory &F,
+ SymbolRef Sym,
+ RangeSet Domain) {
+ APSIntType IntType = BV.getAPSIntType(Sym->getType());
+ return Domain.Intersect(BV, F, ++IntType.getZeroValue(),
+ --IntType.getZeroValue());
+}
+
+/// \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.
+/// \p Input Previously established expression range set
+static RangeSet applyBitwiseConstraints(
+ BasicValueFactory &BV,
+ RangeSet::Factory &F,
+ RangeSet Input,
+ const SymIntExpr* SIE) {
+ QualType T = SIE->getType();
+ bool IsUnsigned = T->isUnsignedIntegerType();
+ const llvm::APSInt &RHS = SIE->getRHS();
+ const llvm::APSInt &Zero = BV.getAPSIntType(T).getZeroValue();
+ BinaryOperator::Opcode Operator = SIE->getOpcode();
+
+ // For unsigned types, the output of bitwise-or is bigger-or-equal than RHS.
+ if (Operator == BO_Or && IsUnsigned)
+ return Input.Intersect(BV, F, RHS, BV.getMaxValue(T));
+
+ // Bitwise-or with a non-zero constant is always non-zero.
+ if (Operator == BO_Or && RHS != Zero)
+ return assumeNonZero(BV, F, SIE, Input);
+
+ // For unsigned types, or positive RHS,
+ // bitwise-and output is always smaller-or-equal than RHS (assuming two's
+ // complement representation of signed types).
+ if (Operator == BO_And && (IsUnsigned || RHS >= Zero))
+ return Input.Intersect(BV, F, BV.getMinValue(T), RHS);
+
+ return Input;
+}
+
RangeSet RangeConstraintManager::getRange(ProgramStateRef State,
SymbolRef Sym) {
if (ConstraintRangeTy::data_type *V = State->get<ConstraintRange>(Sym))
@@ -472,12 +519,13 @@ RangeSet RangeConstraintManager::getRang
RangeSet Result(F, BV.getMinValue(T), BV.getMaxValue(T));
- // Special case: references are known to be non-zero.
- if (T->isReferenceType()) {
- APSIntType IntType = BV.getAPSIntType(T);
- Result = Result.Intersect(BV, F, ++IntType.getZeroValue(),
- --IntType.getZeroValue());
- }
+ // References are known to be non-zero.
+ if (T->isReferenceType())
+ return assumeNonZero(BV, F, Sym, Result);
+
+ // Known constraints on ranges of bitwise expressions.
+ if (const SymIntExpr* SIE = dyn_cast<SymIntExpr>(Sym))
+ return applyBitwiseConstraints(BV, F, Result, SIE);
return Result;
}
Modified: cfe/trunk/test/Analysis/constant-folding.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/constant-folding.c?rev=317820&r1=317819&r2=317820&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/constant-folding.c (original)
+++ cfe/trunk/test/Analysis/constant-folding.c Thu Nov 9 11:06:22 2017
@@ -76,3 +76,42 @@ void testMixedTypeComparisons (char a, u
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) >= 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval((a | -1) >= -1); // expected-warning{{TRUE}}
+ clang_analyzer_eval((a | 2) >= 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval((a | 5) >= 5); // expected-warning{{TRUE}}
+ clang_analyzer_eval((a | 10) >= 10); // expected-warning{{TRUE}}
+
+ // Argument order should not influence this
+ clang_analyzer_eval((1 | a) >= 1); // expected-warning{{TRUE}}
+
+ clang_analyzer_eval((a & 1) <= 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval((a & 2) <= 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval((a & 5) <= 5); // expected-warning{{TRUE}}
+ clang_analyzer_eval((a & 10) <= 10); // expected-warning{{TRUE}}
+ clang_analyzer_eval((a & -10) <= 10); // expected-warning{{UNKNOWN}}
+
+ // Again, check for different argument order.
+ clang_analyzer_eval((1 & a) <= 1); // 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}}
+
+ // Even for signed values, bitwise OR with a non-zero is always non-zero.
+ clang_analyzer_eval((b | 1) == 0); // expected-warning{{FALSE}}
+ clang_analyzer_eval((b | -2) == 0); // expected-warning{{FALSE}}
+ clang_analyzer_eval((b | 10) == 0); // expected-warning{{FALSE}}
+ clang_analyzer_eval((b | 0) == 0); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval((b | -2) >= 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}}
+}
More information about the cfe-commits
mailing list