diff options
-rw-r--r-- | lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp | 32 | ||||
-rw-r--r-- | test/Analysis/ptr-arith.c | 44 |
2 files changed, 61 insertions, 15 deletions
diff --git a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp index d87c51fed3..4ff248785a 100644 --- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp +++ b/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/test/Analysis/ptr-arith.c b/test/Analysis/ptr-arith.c index d9c5a0ff99..35faff4a17 100644 --- a/test/Analysis/ptr-arith.c +++ b/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 //------------------------------- |