summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJordan Rose <jordan_rose@apple.com>2013-03-23 01:21:23 +0000
committerJordan Rose <jordan_rose@apple.com>2013-03-23 01:21:23 +0000
commit59d179e9d2971e8b9abd1d5f01e6815f2ac02b3e (patch)
tree2b0a82d4f94e52800b69813effa42956d22c0c62
parent604d0bbba579e934a10609a4f9cea85170337750 (diff)
downloadbcm5719-llvm-59d179e9d2971e8b9abd1d5f01e6815f2ac02b3e.tar.gz
bcm5719-llvm-59d179e9d2971e8b9abd1d5f01e6815f2ac02b3e.zip
[analyzer] Also transform "a < b" to "(b - a) > 0" in the constraint manager.
We can support the full range of comparison operations between two locations by canonicalizing them as subtraction, as in the previous commit. This won't work (well) if either location includes an offset, or (again) if the comparisons are not consistent about which region comes first. <rdar://problem/13239003> llvm-svn: 177803
-rw-r--r--clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp32
-rw-r--r--clang/test/Analysis/ptr-arith.c44
2 files changed, 61 insertions, 15 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp b/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
index d87c51fed35..4ff248785a5 100644
--- a/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
@@ -50,7 +50,7 @@ bool SimpleConstraintManager::canReasonAbout(SVal X) const {
}
if (const SymSymExpr *SSE = dyn_cast<SymSymExpr>(SE)) {
- if (SSE->getOpcode() == BO_EQ || SSE->getOpcode() == BO_NE)
+ if (BinaryOperator::isComparisonOp(SSE->getOpcode()))
return true;
}
@@ -180,26 +180,28 @@ ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef state,
}
} else if (const SymSymExpr *SSE = dyn_cast<SymSymExpr>(sym)) {
- BinaryOperator::Opcode Op = SSE->getOpcode();
-
// Translate "a != b" to "(b - a) != 0".
// We invert the order of the operands as a heuristic for how loop
// conditions are usually written ("begin != end") as compared to length
// calculations ("end - begin"). The more correct thing to do would be to
// canonicalize "a - b" and "b - a", which would allow us to treat
// "a != b" and "b != a" the same.
- if (BinaryOperator::isEqualityOp(Op)) {
- SymbolManager &SymMgr = getSymbolManager();
-
- assert(Loc::isLocType(SSE->getLHS()->getType()));
- assert(Loc::isLocType(SSE->getRHS()->getType()));
- QualType DiffTy = SymMgr.getContext().getPointerDiffType();
- SymbolRef Subtraction = SymMgr.getSymSymExpr(SSE->getRHS(), BO_Sub,
- SSE->getLHS(), DiffTy);
-
- Assumption ^= (SSE->getOpcode() == BO_EQ);
- return assumeAuxForSymbol(state, Subtraction, Assumption);
- }
+ SymbolManager &SymMgr = getSymbolManager();
+ BinaryOperator::Opcode Op = SSE->getOpcode();
+ assert(BinaryOperator::isComparisonOp(Op));
+
+ // For now, we only support comparing pointers.
+ assert(Loc::isLocType(SSE->getLHS()->getType()));
+ assert(Loc::isLocType(SSE->getRHS()->getType()));
+ QualType DiffTy = SymMgr.getContext().getPointerDiffType();
+ SymbolRef Subtraction = SymMgr.getSymSymExpr(SSE->getRHS(), BO_Sub,
+ SSE->getLHS(), DiffTy);
+
+ const llvm::APSInt &Zero = getBasicVals().getValue(0, DiffTy);
+ Op = BinaryOperator::reverseComparisonOp(Op);
+ if (!Assumption)
+ Op = BinaryOperator::negateComparisonOp(Op);
+ return assumeSymRel(state, Subtraction, Op, Zero);
}
// If we get here, there's nothing else we can do but treat the symbol as
diff --git a/clang/test/Analysis/ptr-arith.c b/clang/test/Analysis/ptr-arith.c
index d9c5a0ff999..35faff4a170 100644
--- a/clang/test/Analysis/ptr-arith.c
+++ b/clang/test/Analysis/ptr-arith.c
@@ -204,6 +204,50 @@ void zero_implies_equal(int *lhs, int *rhs) {
clang_analyzer_eval(lhs != rhs); // expected-warning{{TRUE}}
}
+void comparisons_imply_size(int *lhs, int *rhs) {
+ clang_analyzer_eval(lhs <= rhs); // expected-warning{{UNKNOWN}}
+
+ if (lhs > rhs) {
+ clang_analyzer_eval((rhs - lhs) == 0); // expected-warning{{FALSE}}
+ return;
+ }
+
+ clang_analyzer_eval(lhs <= rhs); // expected-warning{{TRUE}}
+ clang_analyzer_eval((rhs - lhs) >= 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval((rhs - lhs) > 0); // expected-warning{{UNKNOWN}}
+
+ if (lhs >= rhs) {
+ clang_analyzer_eval((rhs - lhs) == 0); // expected-warning{{TRUE}}
+ return;
+ }
+
+ clang_analyzer_eval(lhs == rhs); // expected-warning{{FALSE}}
+ clang_analyzer_eval(lhs < rhs); // expected-warning{{TRUE}}
+ clang_analyzer_eval((rhs - lhs) > 0); // expected-warning{{TRUE}}
+}
+
+void size_implies_comparison(int *lhs, int *rhs) {
+ clang_analyzer_eval(lhs <= rhs); // expected-warning{{UNKNOWN}}
+
+ if ((rhs - lhs) < 0) {
+ clang_analyzer_eval(lhs == rhs); // expected-warning{{FALSE}}
+ return;
+ }
+
+ clang_analyzer_eval(lhs <= rhs); // expected-warning{{TRUE}}
+ clang_analyzer_eval((rhs - lhs) >= 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval((rhs - lhs) > 0); // expected-warning{{UNKNOWN}}
+
+ if ((rhs - lhs) <= 0) {
+ clang_analyzer_eval(lhs == rhs); // expected-warning{{TRUE}}
+ return;
+ }
+
+ clang_analyzer_eval(lhs == rhs); // expected-warning{{FALSE}}
+ clang_analyzer_eval(lhs < rhs); // expected-warning{{TRUE}}
+ clang_analyzer_eval((rhs - lhs) > 0); // expected-warning{{TRUE}}
+}
+
//-------------------------------
// False positives
//-------------------------------
OpenPOWER on IntegriCloud