125b9696bSDonát Nagy //== BitwiseShiftChecker.cpp ------------------------------------*- C++ -*--==// 225b9696bSDonát Nagy // 325b9696bSDonát Nagy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 425b9696bSDonát Nagy // See https://llvm.org/LICENSE.txt for license information. 525b9696bSDonát Nagy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 625b9696bSDonát Nagy // 725b9696bSDonát Nagy //===----------------------------------------------------------------------===// 825b9696bSDonát Nagy // 925b9696bSDonát Nagy // This file defines BitwiseShiftChecker, which is a path-sensitive checker 1025b9696bSDonát Nagy // that looks for undefined behavior when the operands of the bitwise shift 1125b9696bSDonát Nagy // operators '<<' and '>>' are invalid (negative or too large). 1225b9696bSDonát Nagy // 1325b9696bSDonát Nagy //===----------------------------------------------------------------------===// 1425b9696bSDonát Nagy 1525b9696bSDonát Nagy #include "clang/AST/ASTContext.h" 1625b9696bSDonát Nagy #include "clang/AST/CharUnits.h" 1725b9696bSDonát Nagy #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 1825b9696bSDonát Nagy #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 1925b9696bSDonát Nagy #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 2025b9696bSDonát Nagy #include "clang/StaticAnalyzer/Core/Checker.h" 2125b9696bSDonát Nagy #include "clang/StaticAnalyzer/Core/CheckerManager.h" 2225b9696bSDonát Nagy #include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h" 2325b9696bSDonát Nagy #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 2425b9696bSDonát Nagy #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 2525b9696bSDonát Nagy #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" 2625b9696bSDonát Nagy #include "llvm/Support/FormatVariadic.h" 2725b9696bSDonát Nagy #include <memory> 2825b9696bSDonát Nagy 2925b9696bSDonát Nagy using namespace clang; 3025b9696bSDonát Nagy using namespace ento; 3125b9696bSDonát Nagy using llvm::formatv; 3225b9696bSDonát Nagy 3325b9696bSDonát Nagy namespace { 3425b9696bSDonát Nagy enum class OperandSide { Left, Right }; 3525b9696bSDonát Nagy 3625b9696bSDonát Nagy using BugReportPtr = std::unique_ptr<PathSensitiveBugReport>; 3725b9696bSDonát Nagy 3825b9696bSDonát Nagy struct NoteTagTemplate { 3925b9696bSDonát Nagy llvm::StringLiteral SignInfo; 4025b9696bSDonát Nagy llvm::StringLiteral UpperBoundIntro; 4125b9696bSDonát Nagy }; 4225b9696bSDonát Nagy 4325b9696bSDonát Nagy constexpr NoteTagTemplate NoteTagTemplates[] = { 4425b9696bSDonát Nagy {"", "right operand of bit shift is less than "}, 4525b9696bSDonát Nagy {"left operand of bit shift is non-negative", " and right operand is less than "}, 4625b9696bSDonát Nagy {"right operand of bit shift is non-negative", " but less than "}, 4725b9696bSDonát Nagy {"both operands of bit shift are non-negative", " and right operand is less than "} 4825b9696bSDonát Nagy }; 4925b9696bSDonát Nagy 5025b9696bSDonát Nagy /// An implementation detail class which is introduced to split the checker 5125b9696bSDonát Nagy /// logic into several methods while maintaining a consistently updated state 5225b9696bSDonát Nagy /// and access to other contextual data. 5325b9696bSDonát Nagy class BitwiseShiftValidator { 5425b9696bSDonát Nagy CheckerContext &Ctx; 5525b9696bSDonát Nagy ProgramStateRef FoldedState; 5625b9696bSDonát Nagy const BinaryOperator *const Op; 5725b9696bSDonát Nagy const BugType &BT; 5825b9696bSDonát Nagy const bool PedanticFlag; 5925b9696bSDonát Nagy 6025b9696bSDonát Nagy // The following data members are only used for note tag creation: 6125b9696bSDonát Nagy enum { NonNegLeft = 1, NonNegRight = 2 }; 6225b9696bSDonát Nagy unsigned NonNegOperands = 0; 6325b9696bSDonát Nagy 6425b9696bSDonát Nagy std::optional<unsigned> UpperBoundBitCount = std::nullopt; 6525b9696bSDonát Nagy 6625b9696bSDonát Nagy public: 6725b9696bSDonát Nagy BitwiseShiftValidator(const BinaryOperator *O, CheckerContext &C, 6825b9696bSDonát Nagy const BugType &B, bool P) 6925b9696bSDonát Nagy : Ctx(C), FoldedState(C.getState()), Op(O), BT(B), PedanticFlag(P) {} 7025b9696bSDonát Nagy void run(); 7125b9696bSDonát Nagy 7225b9696bSDonát Nagy private: 7325b9696bSDonát Nagy const Expr *operandExpr(OperandSide Side) const { 7425b9696bSDonát Nagy return Side == OperandSide::Left ? Op->getLHS() : Op->getRHS(); 7525b9696bSDonát Nagy } 7625b9696bSDonát Nagy 7725b9696bSDonát Nagy bool shouldPerformPedanticChecks() const { 7825b9696bSDonát Nagy // The pedantic flag has no effect under C++20 because the affected issues 7925b9696bSDonát Nagy // are no longer undefined under that version of the standard. 8025b9696bSDonát Nagy return PedanticFlag && !Ctx.getASTContext().getLangOpts().CPlusPlus20; 8125b9696bSDonát Nagy } 8225b9696bSDonát Nagy 8325b9696bSDonát Nagy bool assumeRequirement(OperandSide Side, BinaryOperator::Opcode Cmp, unsigned Limit); 8425b9696bSDonát Nagy 8525b9696bSDonát Nagy void recordAssumption(OperandSide Side, BinaryOperator::Opcode Cmp, unsigned Limit); 8625b9696bSDonát Nagy const NoteTag *createNoteTag() const; 8725b9696bSDonát Nagy 8825b9696bSDonát Nagy BugReportPtr createBugReport(StringRef ShortMsg, StringRef Msg) const; 8925b9696bSDonát Nagy 9025b9696bSDonát Nagy BugReportPtr checkOvershift(); 9125b9696bSDonát Nagy BugReportPtr checkOperandNegative(OperandSide Side); 9225b9696bSDonát Nagy BugReportPtr checkLeftShiftOverflow(); 9325b9696bSDonát Nagy 9425b9696bSDonát Nagy bool isLeftShift() const { return Op->getOpcode() == BO_Shl; } 9525b9696bSDonát Nagy StringRef shiftDir() const { return isLeftShift() ? "left" : "right"; } 9625b9696bSDonát Nagy static StringRef pluralSuffix(unsigned n) { return n <= 1 ? "" : "s"; } 9725b9696bSDonát Nagy static StringRef verbSuffix(unsigned n) { return n <= 1 ? "s" : ""; } 9825b9696bSDonát Nagy }; 9925b9696bSDonát Nagy 10025b9696bSDonát Nagy void BitwiseShiftValidator::run() { 10125b9696bSDonát Nagy // Report a bug if the right operand is >= the bit width of the type of the 10225b9696bSDonát Nagy // left operand: 10325b9696bSDonát Nagy if (BugReportPtr BR = checkOvershift()) { 10425b9696bSDonát Nagy Ctx.emitReport(std::move(BR)); 10525b9696bSDonát Nagy return; 10625b9696bSDonát Nagy } 10725b9696bSDonát Nagy 10825b9696bSDonát Nagy // Report a bug if the right operand is negative: 10925b9696bSDonát Nagy if (BugReportPtr BR = checkOperandNegative(OperandSide::Right)) { 11025b9696bSDonát Nagy Ctx.emitReport(std::move(BR)); 11125b9696bSDonát Nagy return; 11225b9696bSDonát Nagy } 11325b9696bSDonát Nagy 11425b9696bSDonát Nagy if (shouldPerformPedanticChecks()) { 11525b9696bSDonát Nagy // Report a bug if the left operand is negative: 11625b9696bSDonát Nagy if (BugReportPtr BR = checkOperandNegative(OperandSide::Left)) { 11725b9696bSDonát Nagy Ctx.emitReport(std::move(BR)); 11825b9696bSDonát Nagy return; 11925b9696bSDonát Nagy } 12025b9696bSDonát Nagy 12125b9696bSDonát Nagy // Report a bug when left shift of a concrete signed value overflows: 12225b9696bSDonát Nagy if (BugReportPtr BR = checkLeftShiftOverflow()) { 12325b9696bSDonát Nagy Ctx.emitReport(std::move(BR)); 12425b9696bSDonát Nagy return; 12525b9696bSDonát Nagy } 12625b9696bSDonát Nagy } 12725b9696bSDonát Nagy 12825b9696bSDonát Nagy // No bugs detected, update the state and add a single note tag which 12925b9696bSDonát Nagy // summarizes the new assumptions. 13025b9696bSDonát Nagy Ctx.addTransition(FoldedState, createNoteTag()); 13125b9696bSDonát Nagy } 13225b9696bSDonát Nagy 13325b9696bSDonát Nagy /// This method checks a requirement that must be satisfied by the value on the 13425b9696bSDonát Nagy /// given Side of a bitwise shift operator in well-defined code. If the 13525b9696bSDonát Nagy /// requirement is incompatible with prior knowledge, this method reports 13625b9696bSDonát Nagy /// failure by returning false. 13725b9696bSDonát Nagy bool BitwiseShiftValidator::assumeRequirement(OperandSide Side, 13825b9696bSDonát Nagy BinaryOperator::Opcode Comparison, 13925b9696bSDonát Nagy unsigned Limit) { 14025b9696bSDonát Nagy SValBuilder &SVB = Ctx.getSValBuilder(); 14125b9696bSDonát Nagy 14225b9696bSDonát Nagy const SVal OperandVal = Ctx.getSVal(operandExpr(Side)); 14325b9696bSDonát Nagy const auto LimitVal = SVB.makeIntVal(Limit, Ctx.getASTContext().IntTy); 14425b9696bSDonát Nagy // Note that the type of `LimitVal` must be a signed, because otherwise a 14525b9696bSDonát Nagy // negative `Val` could be converted to a large positive value. 14625b9696bSDonát Nagy 14725b9696bSDonát Nagy auto ResultVal = SVB.evalBinOp(FoldedState, Comparison, OperandVal, LimitVal, 14825b9696bSDonát Nagy SVB.getConditionType()); 14925b9696bSDonát Nagy if (auto DURes = ResultVal.getAs<DefinedOrUnknownSVal>()) { 15025b9696bSDonát Nagy auto [StTrue, StFalse] = FoldedState->assume(DURes.value()); 15125b9696bSDonát Nagy if (!StTrue) { 15225b9696bSDonát Nagy // We detected undefined behavior (the caller will report it). 15325b9696bSDonát Nagy FoldedState = StFalse; 15425b9696bSDonát Nagy return false; 15525b9696bSDonát Nagy } 15625b9696bSDonát Nagy // The code may be valid, so let's assume that it's valid: 15725b9696bSDonát Nagy FoldedState = StTrue; 15825b9696bSDonát Nagy if (StFalse) { 15925b9696bSDonát Nagy // Record note tag data for the assumption that we made 16025b9696bSDonát Nagy recordAssumption(Side, Comparison, Limit); 16125b9696bSDonát Nagy } 16225b9696bSDonát Nagy } 16325b9696bSDonát Nagy return true; 16425b9696bSDonát Nagy } 16525b9696bSDonát Nagy 16625b9696bSDonát Nagy BugReportPtr BitwiseShiftValidator::checkOvershift() { 16725b9696bSDonát Nagy const QualType LHSTy = Op->getLHS()->getType(); 16825b9696bSDonát Nagy const unsigned LHSBitWidth = Ctx.getASTContext().getIntWidth(LHSTy); 16925b9696bSDonát Nagy 17025b9696bSDonát Nagy if (assumeRequirement(OperandSide::Right, BO_LT, LHSBitWidth)) 17125b9696bSDonát Nagy return nullptr; 17225b9696bSDonát Nagy 17325b9696bSDonát Nagy const SVal Right = Ctx.getSVal(operandExpr(OperandSide::Right)); 17425b9696bSDonát Nagy 175*67f387c6SDonatNagyE std::string RightOpStr = "", LowerBoundStr = ""; 17625b9696bSDonát Nagy if (auto ConcreteRight = Right.getAs<nonloc::ConcreteInt>()) 17725b9696bSDonát Nagy RightOpStr = formatv(" '{0}'", ConcreteRight->getValue()); 178*67f387c6SDonatNagyE else { 179*67f387c6SDonatNagyE SValBuilder &SVB = Ctx.getSValBuilder(); 180*67f387c6SDonatNagyE if (const llvm::APSInt *MinRight = SVB.getMinValue(FoldedState, Right)) { 181*67f387c6SDonatNagyE LowerBoundStr = formatv(" >= {0},", MinRight->getExtValue()); 182*67f387c6SDonatNagyE } 183*67f387c6SDonatNagyE } 18425b9696bSDonát Nagy 18525b9696bSDonát Nagy std::string ShortMsg = formatv( 18625b9696bSDonát Nagy "{0} shift{1}{2} overflows the capacity of '{3}'", 18725b9696bSDonát Nagy isLeftShift() ? "Left" : "Right", RightOpStr.empty() ? "" : " by", 18825b9696bSDonát Nagy RightOpStr, LHSTy.getAsString()); 189*67f387c6SDonatNagyE std::string Msg = formatv( 190*67f387c6SDonatNagyE "The result of {0} shift is undefined because the right " 191*67f387c6SDonatNagyE "operand{1} is{2} not smaller than {3}, the capacity of '{4}'", 192*67f387c6SDonatNagyE shiftDir(), RightOpStr, LowerBoundStr, LHSBitWidth, LHSTy.getAsString()); 19325b9696bSDonát Nagy return createBugReport(ShortMsg, Msg); 19425b9696bSDonát Nagy } 19525b9696bSDonát Nagy 19625b9696bSDonát Nagy // Before C++20, at 5.8 [expr.shift] (N4296, 2014-11-19) the standard says 19725b9696bSDonát Nagy // 1. "... The behaviour is undefined if the right operand is negative..." 19825b9696bSDonát Nagy // 2. "The value of E1 << E2 ... 19925b9696bSDonát Nagy // if E1 has a signed type and non-negative value ... 20025b9696bSDonát Nagy // otherwise, the behavior is undefined." 20125b9696bSDonát Nagy // 3. "The value of E1 >> E2 ... 20225b9696bSDonát Nagy // If E1 has a signed type and a negative value, 20325b9696bSDonát Nagy // the resulting value is implementation-defined." 20425b9696bSDonát Nagy // However, negative left arguments work in practice and the C++20 standard 20525b9696bSDonát Nagy // eliminates conditions 2 and 3. 20625b9696bSDonát Nagy BugReportPtr BitwiseShiftValidator::checkOperandNegative(OperandSide Side) { 20725b9696bSDonát Nagy // If the type is unsigned, it cannot be negative 20825b9696bSDonát Nagy if (!operandExpr(Side)->getType()->isSignedIntegerType()) 20925b9696bSDonát Nagy return nullptr; 21025b9696bSDonát Nagy 21125b9696bSDonát Nagy // Main check: determine whether the operand is constrained to be negative 21225b9696bSDonát Nagy if (assumeRequirement(Side, BO_GE, 0)) 21325b9696bSDonát Nagy return nullptr; 21425b9696bSDonát Nagy 21525b9696bSDonát Nagy std::string ShortMsg = formatv("{0} operand is negative in {1} shift", 21625b9696bSDonát Nagy Side == OperandSide::Left ? "Left" : "Right", 21725b9696bSDonát Nagy shiftDir()) 21825b9696bSDonát Nagy .str(); 21925b9696bSDonát Nagy std::string Msg = formatv("The result of {0} shift is undefined " 22025b9696bSDonát Nagy "because the {1} operand is negative", 22125b9696bSDonát Nagy shiftDir(), 22225b9696bSDonát Nagy Side == OperandSide::Left ? "left" : "right") 22325b9696bSDonát Nagy .str(); 22425b9696bSDonát Nagy 22525b9696bSDonát Nagy return createBugReport(ShortMsg, Msg); 22625b9696bSDonát Nagy } 22725b9696bSDonát Nagy 22825b9696bSDonát Nagy BugReportPtr BitwiseShiftValidator::checkLeftShiftOverflow() { 22925b9696bSDonát Nagy // A right shift cannot be an overflowing left shift... 23025b9696bSDonát Nagy if (!isLeftShift()) 23125b9696bSDonát Nagy return nullptr; 23225b9696bSDonát Nagy 23325b9696bSDonát Nagy // In C++ it's well-defined to shift to the sign bit. In C however, it's UB. 23425b9696bSDonát Nagy // 5.8.2 [expr.shift] (N4296, 2014-11-19) 23525b9696bSDonát Nagy const bool ShouldPreserveSignBit = !Ctx.getLangOpts().CPlusPlus; 23625b9696bSDonát Nagy 23725b9696bSDonát Nagy const Expr *LHS = operandExpr(OperandSide::Left); 23825b9696bSDonát Nagy const QualType LHSTy = LHS->getType(); 23925b9696bSDonát Nagy const unsigned LeftBitWidth = Ctx.getASTContext().getIntWidth(LHSTy); 24025b9696bSDonát Nagy assert(LeftBitWidth > 0); 24125b9696bSDonát Nagy 24225b9696bSDonát Nagy // Quote "For unsigned lhs, the value of LHS << RHS is the value of LHS * 24325b9696bSDonát Nagy // 2^RHS, reduced modulo maximum value of the return type plus 1." 24425b9696bSDonát Nagy if (LHSTy->isUnsignedIntegerType()) 24525b9696bSDonát Nagy return nullptr; 24625b9696bSDonát Nagy 24725b9696bSDonát Nagy // We only support concrete integers as left operand. 24825b9696bSDonát Nagy const auto Left = Ctx.getSVal(LHS).getAs<nonloc::ConcreteInt>(); 24925b9696bSDonát Nagy if (!Left.has_value()) 25025b9696bSDonát Nagy return nullptr; 25125b9696bSDonát Nagy 25225b9696bSDonát Nagy // We should have already reported a bug if the left operand of the shift was 25325b9696bSDonát Nagy // negative, so it cannot be negative here. 25425b9696bSDonát Nagy assert(Left->getValue().isNonNegative()); 25525b9696bSDonát Nagy 25625b9696bSDonát Nagy const unsigned LeftAvailableBitWidth = 25725b9696bSDonát Nagy LeftBitWidth - static_cast<unsigned>(ShouldPreserveSignBit); 25825b9696bSDonát Nagy const unsigned UsedBitsInLeftOperand = Left->getValue().getActiveBits(); 25925b9696bSDonát Nagy assert(LeftBitWidth >= UsedBitsInLeftOperand); 26025b9696bSDonát Nagy const unsigned MaximalAllowedShift = 26125b9696bSDonát Nagy LeftAvailableBitWidth - UsedBitsInLeftOperand; 26225b9696bSDonát Nagy 26325b9696bSDonát Nagy if (assumeRequirement(OperandSide::Right, BO_LT, MaximalAllowedShift + 1)) 26425b9696bSDonát Nagy return nullptr; 26525b9696bSDonát Nagy 26625b9696bSDonát Nagy const std::string CapacityMsg = 26725b9696bSDonát Nagy formatv("because '{0}' can hold only {1} bits ({2} the sign bit)", 26825b9696bSDonát Nagy LHSTy.getAsString(), LeftAvailableBitWidth, 26925b9696bSDonát Nagy ShouldPreserveSignBit ? "excluding" : "including"); 27025b9696bSDonát Nagy 27125b9696bSDonát Nagy const SVal Right = Ctx.getSVal(Op->getRHS()); 27225b9696bSDonát Nagy 27325b9696bSDonát Nagy std::string ShortMsg, Msg; 27425b9696bSDonát Nagy if (const auto ConcreteRight = Right.getAs<nonloc::ConcreteInt>()) { 27525b9696bSDonát Nagy // Here ConcreteRight must contain a small non-negative integer, because 27625b9696bSDonát Nagy // otherwise one of the earlier checks should've reported a bug. 27725b9696bSDonát Nagy const unsigned RHS = ConcreteRight->getValue().getExtValue(); 27825b9696bSDonát Nagy assert(RHS > MaximalAllowedShift); 27925b9696bSDonát Nagy const unsigned OverflownBits = RHS - MaximalAllowedShift; 28025b9696bSDonát Nagy ShortMsg = formatv( 28125b9696bSDonát Nagy "The shift '{0} << {1}' overflows the capacity of '{2}'", 28225b9696bSDonát Nagy Left->getValue(), ConcreteRight->getValue(), LHSTy.getAsString()); 28325b9696bSDonát Nagy Msg = formatv( 28425b9696bSDonát Nagy "The shift '{0} << {1}' is undefined {2}, so {3} bit{4} overflow{5}", 28525b9696bSDonát Nagy Left->getValue(), ConcreteRight->getValue(), CapacityMsg, OverflownBits, 28625b9696bSDonát Nagy pluralSuffix(OverflownBits), verbSuffix(OverflownBits)); 28725b9696bSDonát Nagy } else { 28825b9696bSDonát Nagy ShortMsg = formatv("Left shift of '{0}' overflows the capacity of '{1}'", 28925b9696bSDonát Nagy Left->getValue(), LHSTy.getAsString()); 29025b9696bSDonát Nagy Msg = formatv( 29125b9696bSDonát Nagy "Left shift of '{0}' is undefined {1}, so some bits overflow", 29225b9696bSDonát Nagy Left->getValue(), CapacityMsg); 29325b9696bSDonát Nagy } 29425b9696bSDonát Nagy 29525b9696bSDonát Nagy return createBugReport(ShortMsg, Msg); 29625b9696bSDonát Nagy } 29725b9696bSDonát Nagy 29825b9696bSDonát Nagy void BitwiseShiftValidator::recordAssumption(OperandSide Side, 29925b9696bSDonát Nagy BinaryOperator::Opcode Comparison, 30025b9696bSDonát Nagy unsigned Limit) { 30125b9696bSDonát Nagy switch (Comparison) { 30225b9696bSDonát Nagy case BO_GE: 30325b9696bSDonát Nagy assert(Limit == 0); 30425b9696bSDonát Nagy NonNegOperands |= (Side == OperandSide::Left ? NonNegLeft : NonNegRight); 30525b9696bSDonát Nagy break; 30625b9696bSDonát Nagy case BO_LT: 30725b9696bSDonát Nagy assert(Side == OperandSide::Right); 30825b9696bSDonát Nagy if (!UpperBoundBitCount || Limit < UpperBoundBitCount.value()) 30925b9696bSDonát Nagy UpperBoundBitCount = Limit; 31025b9696bSDonát Nagy break; 31125b9696bSDonát Nagy default: 31225b9696bSDonát Nagy llvm_unreachable("this checker does not use other comparison operators"); 31325b9696bSDonát Nagy } 31425b9696bSDonát Nagy } 31525b9696bSDonát Nagy 31625b9696bSDonát Nagy const NoteTag *BitwiseShiftValidator::createNoteTag() const { 31725b9696bSDonát Nagy if (!NonNegOperands && !UpperBoundBitCount) 31825b9696bSDonát Nagy return nullptr; 31925b9696bSDonát Nagy 32025b9696bSDonát Nagy SmallString<128> Buf; 32125b9696bSDonát Nagy llvm::raw_svector_ostream Out(Buf); 32225b9696bSDonát Nagy Out << "Assuming "; 32325b9696bSDonát Nagy NoteTagTemplate Templ = NoteTagTemplates[NonNegOperands]; 32425b9696bSDonát Nagy Out << Templ.SignInfo; 32525b9696bSDonát Nagy if (UpperBoundBitCount) 32625b9696bSDonát Nagy Out << Templ.UpperBoundIntro << UpperBoundBitCount.value(); 32725b9696bSDonát Nagy const std::string Msg(Out.str()); 32825b9696bSDonát Nagy 32925b9696bSDonát Nagy return Ctx.getNoteTag(Msg, /*isPrunable=*/true); 33025b9696bSDonát Nagy } 33125b9696bSDonát Nagy 33225b9696bSDonát Nagy std::unique_ptr<PathSensitiveBugReport> 33325b9696bSDonát Nagy BitwiseShiftValidator::createBugReport(StringRef ShortMsg, StringRef Msg) const { 33425b9696bSDonát Nagy ProgramStateRef State = Ctx.getState(); 33525b9696bSDonát Nagy if (ExplodedNode *ErrNode = Ctx.generateErrorNode(State)) { 33625b9696bSDonát Nagy auto BR = 33725b9696bSDonát Nagy std::make_unique<PathSensitiveBugReport>(BT, ShortMsg, Msg, ErrNode); 33825b9696bSDonát Nagy bugreporter::trackExpressionValue(ErrNode, Op->getLHS(), *BR); 33925b9696bSDonát Nagy bugreporter::trackExpressionValue(ErrNode, Op->getRHS(), *BR); 34025b9696bSDonát Nagy return BR; 34125b9696bSDonát Nagy } 34225b9696bSDonát Nagy return nullptr; 34325b9696bSDonát Nagy } 34425b9696bSDonát Nagy } // anonymous namespace 34525b9696bSDonát Nagy 34625b9696bSDonát Nagy class BitwiseShiftChecker : public Checker<check::PreStmt<BinaryOperator>> { 34725b9696bSDonát Nagy mutable std::unique_ptr<BugType> BTPtr; 34825b9696bSDonát Nagy 34925b9696bSDonát Nagy public: 35025b9696bSDonát Nagy void checkPreStmt(const BinaryOperator *B, CheckerContext &Ctx) const { 35125b9696bSDonát Nagy BinaryOperator::Opcode Op = B->getOpcode(); 35225b9696bSDonát Nagy 35325b9696bSDonát Nagy if (Op != BO_Shl && Op != BO_Shr) 35425b9696bSDonát Nagy return; 35525b9696bSDonát Nagy 35625b9696bSDonát Nagy if (!BTPtr) 35725b9696bSDonát Nagy BTPtr = std::make_unique<BugType>(this, "Bitwise shift", 35825b9696bSDonát Nagy "Suspicious operation"); 35925b9696bSDonát Nagy 36025b9696bSDonát Nagy BitwiseShiftValidator(B, Ctx, *BTPtr, Pedantic).run(); 36125b9696bSDonát Nagy } 36225b9696bSDonát Nagy 36325b9696bSDonát Nagy bool Pedantic = false; 36425b9696bSDonát Nagy }; 36525b9696bSDonát Nagy 36625b9696bSDonát Nagy void ento::registerBitwiseShiftChecker(CheckerManager &Mgr) { 36725b9696bSDonát Nagy auto *Chk = Mgr.registerChecker<BitwiseShiftChecker>(); 36825b9696bSDonát Nagy const AnalyzerOptions &Opts = Mgr.getAnalyzerOptions(); 36925b9696bSDonát Nagy Chk->Pedantic = Opts.getCheckerBooleanOption(Chk, "Pedantic"); 37025b9696bSDonát Nagy } 37125b9696bSDonát Nagy 37225b9696bSDonát Nagy bool ento::shouldRegisterBitwiseShiftChecker(const CheckerManager &mgr) { 37325b9696bSDonát Nagy return true; 37425b9696bSDonát Nagy } 375