diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:11:37 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:11:37 +0000 |
commit | 461a67fa15370a9ec88f8f8a240bf7c123bb2029 (patch) | |
tree | 6942083d7d56bba40ec790a453ca58ad3baf6832 /lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp | |
parent | 75c3240472ba6ac2669ee72ca67eb72d4e2851fc (diff) |
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp | 51 |
1 files changed, 44 insertions, 7 deletions
diff --git a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp index f3c2ffc58662..172ce346f1ba 100644 --- a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp @@ -59,6 +59,11 @@ static bool isArrayIndexOutOfBounds(CheckerContext &C, const Expr *Ex) { return StOutBound && !StInBound; } +static bool isShiftOverflow(const BinaryOperator *B, CheckerContext &C) { + return C.isGreaterOrEqual( + B->getRHS(), C.getASTContext().getIntWidth(B->getLHS()->getType())); +} + void UndefResultChecker::checkPostStmt(const BinaryOperator *B, CheckerContext &C) const { ProgramStateRef state = C.getState(); @@ -97,18 +102,50 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B, } if (Ex) { - OS << "The " << (isLeft ? "left" : "right") - << " operand of '" + OS << "The " << (isLeft ? "left" : "right") << " operand of '" << BinaryOperator::getOpcodeStr(B->getOpcode()) << "' is a garbage value"; if (isArrayIndexOutOfBounds(C, Ex)) OS << " due to array index out of bounds"; - } - else { + } else { // Neither operand was undefined, but the result is undefined. - OS << "The result of the '" - << BinaryOperator::getOpcodeStr(B->getOpcode()) - << "' expression is undefined"; + if ((B->getOpcode() == BinaryOperatorKind::BO_Shl || + B->getOpcode() == BinaryOperatorKind::BO_Shr) && + C.isNegative(B->getRHS())) { + OS << "The result of the " + << ((B->getOpcode() == BinaryOperatorKind::BO_Shl) ? "left" + : "right") + << " shift is undefined because the right operand is negative"; + } else if ((B->getOpcode() == BinaryOperatorKind::BO_Shl || + B->getOpcode() == BinaryOperatorKind::BO_Shr) && + isShiftOverflow(B, C)) { + + OS << "The result of the " + << ((B->getOpcode() == BinaryOperatorKind::BO_Shl) ? "left" + : "right") + << " shift is undefined due to shifting by "; + + SValBuilder &SB = C.getSValBuilder(); + const llvm::APSInt *I = + SB.getKnownValue(C.getState(), C.getSVal(B->getRHS())); + if (!I) + OS << "a value that is"; + else if (I->isUnsigned()) + OS << '\'' << I->getZExtValue() << "\', which is"; + else + OS << '\'' << I->getSExtValue() << "\', which is"; + + OS << " greater or equal to the width of type '" + << B->getLHS()->getType().getAsString() << "'."; + } else if (B->getOpcode() == BinaryOperatorKind::BO_Shl && + C.isNegative(B->getLHS())) { + OS << "The result of the left shift is undefined because the left " + "operand is negative"; + } else { + OS << "The result of the '" + << BinaryOperator::getOpcodeStr(B->getOpcode()) + << "' expression is undefined"; + } } auto report = llvm::make_unique<BugReport>(*BT, OS.str(), N); if (Ex) { |