xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/BitwiseShiftChecker.cpp (revision d0d5101f9959013e42f6f07d79d0fe638aaa0aa3)
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 
17567f387c6SDonatNagyE   std::string RightOpStr = "", LowerBoundStr = "";
17625b9696bSDonát Nagy   if (auto ConcreteRight = Right.getAs<nonloc::ConcreteInt>())
17725b9696bSDonát Nagy     RightOpStr = formatv(" '{0}'", ConcreteRight->getValue());
17867f387c6SDonatNagyE   else {
17967f387c6SDonatNagyE     SValBuilder &SVB = Ctx.getSValBuilder();
1804995d093SBalazs Benics     if (const llvm::APSInt *MinRight = SVB.getMinValue(FoldedState, Right);
1814995d093SBalazs Benics         MinRight && *MinRight >= LHSBitWidth) {
18267f387c6SDonatNagyE       LowerBoundStr = formatv(" >= {0},", MinRight->getExtValue());
18367f387c6SDonatNagyE     }
18467f387c6SDonatNagyE   }
18525b9696bSDonát Nagy 
18625b9696bSDonát Nagy   std::string ShortMsg = formatv(
18725b9696bSDonát Nagy       "{0} shift{1}{2} overflows the capacity of '{3}'",
18825b9696bSDonát Nagy       isLeftShift() ? "Left" : "Right", RightOpStr.empty() ? "" : " by",
18925b9696bSDonát Nagy       RightOpStr, LHSTy.getAsString());
19067f387c6SDonatNagyE   std::string Msg = formatv(
19167f387c6SDonatNagyE       "The result of {0} shift is undefined because the right "
19267f387c6SDonatNagyE       "operand{1} is{2} not smaller than {3}, the capacity of '{4}'",
19367f387c6SDonatNagyE       shiftDir(), RightOpStr, LowerBoundStr, LHSBitWidth, LHSTy.getAsString());
19425b9696bSDonát Nagy   return createBugReport(ShortMsg, Msg);
19525b9696bSDonát Nagy }
19625b9696bSDonát Nagy 
19725b9696bSDonát Nagy // Before C++20, at 5.8 [expr.shift] (N4296, 2014-11-19) the standard says
19825b9696bSDonát Nagy // 1. "... The behaviour is undefined if the right operand is negative..."
19925b9696bSDonát Nagy // 2. "The value of E1 << E2 ...
20025b9696bSDonát Nagy //     if E1 has a signed type and non-negative value ...
20125b9696bSDonát Nagy //     otherwise, the behavior is undefined."
20225b9696bSDonát Nagy // 3. "The value of E1 >> E2 ...
20325b9696bSDonát Nagy //     If E1 has a signed type and a negative value,
20425b9696bSDonát Nagy //     the resulting value is implementation-defined."
20525b9696bSDonát Nagy // However, negative left arguments work in practice and the C++20 standard
20625b9696bSDonát Nagy // eliminates conditions 2 and 3.
20725b9696bSDonát Nagy BugReportPtr BitwiseShiftValidator::checkOperandNegative(OperandSide Side) {
20825b9696bSDonát Nagy   // If the type is unsigned, it cannot be negative
20925b9696bSDonát Nagy   if (!operandExpr(Side)->getType()->isSignedIntegerType())
21025b9696bSDonát Nagy     return nullptr;
21125b9696bSDonát Nagy 
21225b9696bSDonát Nagy   // Main check: determine whether the operand is constrained to be negative
21325b9696bSDonát Nagy   if (assumeRequirement(Side, BO_GE, 0))
21425b9696bSDonát Nagy     return nullptr;
21525b9696bSDonát Nagy 
21625b9696bSDonát Nagy   std::string ShortMsg = formatv("{0} operand is negative in {1} shift",
21725b9696bSDonát Nagy                                  Side == OperandSide::Left ? "Left" : "Right",
21825b9696bSDonát Nagy                                  shiftDir())
21925b9696bSDonát Nagy                              .str();
22025b9696bSDonát Nagy   std::string Msg = formatv("The result of {0} shift is undefined "
22125b9696bSDonát Nagy                             "because the {1} operand is negative",
22225b9696bSDonát Nagy                             shiftDir(),
22325b9696bSDonát Nagy                             Side == OperandSide::Left ? "left" : "right")
22425b9696bSDonát Nagy                         .str();
22525b9696bSDonát Nagy 
22625b9696bSDonát Nagy   return createBugReport(ShortMsg, Msg);
22725b9696bSDonát Nagy }
22825b9696bSDonát Nagy 
22925b9696bSDonát Nagy BugReportPtr BitwiseShiftValidator::checkLeftShiftOverflow() {
23025b9696bSDonát Nagy   // A right shift cannot be an overflowing left shift...
23125b9696bSDonát Nagy   if (!isLeftShift())
23225b9696bSDonát Nagy     return nullptr;
23325b9696bSDonát Nagy 
23425b9696bSDonát Nagy   // In C++ it's well-defined to shift to the sign bit. In C however, it's UB.
23525b9696bSDonát Nagy   // 5.8.2 [expr.shift] (N4296, 2014-11-19)
23625b9696bSDonát Nagy   const bool ShouldPreserveSignBit = !Ctx.getLangOpts().CPlusPlus;
23725b9696bSDonát Nagy 
23825b9696bSDonát Nagy   const Expr *LHS = operandExpr(OperandSide::Left);
23925b9696bSDonát Nagy   const QualType LHSTy = LHS->getType();
24025b9696bSDonát Nagy   const unsigned LeftBitWidth = Ctx.getASTContext().getIntWidth(LHSTy);
24125b9696bSDonát Nagy   assert(LeftBitWidth > 0);
24225b9696bSDonát Nagy 
24325b9696bSDonát Nagy   // Quote "For unsigned lhs, the value of LHS << RHS is the value of LHS *
24425b9696bSDonát Nagy   // 2^RHS, reduced modulo maximum value of the return type plus 1."
24525b9696bSDonát Nagy   if (LHSTy->isUnsignedIntegerType())
24625b9696bSDonát Nagy     return nullptr;
24725b9696bSDonát Nagy 
24825b9696bSDonát Nagy   // We only support concrete integers as left operand.
24925b9696bSDonát Nagy   const auto Left = Ctx.getSVal(LHS).getAs<nonloc::ConcreteInt>();
25025b9696bSDonát Nagy   if (!Left.has_value())
25125b9696bSDonát Nagy     return nullptr;
25225b9696bSDonát Nagy 
25325b9696bSDonát Nagy   // We should have already reported a bug if the left operand of the shift was
25425b9696bSDonát Nagy   // negative, so it cannot be negative here.
255*d0d5101fSBalazs Benics   assert(Left->getValue()->isNonNegative());
25625b9696bSDonát Nagy 
25725b9696bSDonát Nagy   const unsigned LeftAvailableBitWidth =
25825b9696bSDonát Nagy       LeftBitWidth - static_cast<unsigned>(ShouldPreserveSignBit);
259*d0d5101fSBalazs Benics   const unsigned UsedBitsInLeftOperand = Left->getValue()->getActiveBits();
26025b9696bSDonát Nagy   assert(LeftBitWidth >= UsedBitsInLeftOperand);
26125b9696bSDonát Nagy   const unsigned MaximalAllowedShift =
26225b9696bSDonát Nagy       LeftAvailableBitWidth - UsedBitsInLeftOperand;
26325b9696bSDonát Nagy 
26425b9696bSDonát Nagy   if (assumeRequirement(OperandSide::Right, BO_LT, MaximalAllowedShift + 1))
26525b9696bSDonát Nagy     return nullptr;
26625b9696bSDonát Nagy 
26725b9696bSDonát Nagy   const std::string CapacityMsg =
26825b9696bSDonát Nagy       formatv("because '{0}' can hold only {1} bits ({2} the sign bit)",
26925b9696bSDonát Nagy                     LHSTy.getAsString(), LeftAvailableBitWidth,
27025b9696bSDonát Nagy                     ShouldPreserveSignBit ? "excluding" : "including");
27125b9696bSDonát Nagy 
27225b9696bSDonát Nagy   const SVal Right = Ctx.getSVal(Op->getRHS());
27325b9696bSDonát Nagy 
27425b9696bSDonát Nagy   std::string ShortMsg, Msg;
27525b9696bSDonát Nagy   if (const auto ConcreteRight = Right.getAs<nonloc::ConcreteInt>()) {
27625b9696bSDonát Nagy     // Here ConcreteRight must contain a small non-negative integer, because
27725b9696bSDonát Nagy     // otherwise one of the earlier checks should've reported a bug.
278*d0d5101fSBalazs Benics     const int64_t RHS = ConcreteRight->getValue()->getExtValue();
27925b9696bSDonát Nagy     assert(RHS > MaximalAllowedShift);
280*d0d5101fSBalazs Benics     const int64_t OverflownBits = RHS - MaximalAllowedShift;
28125b9696bSDonát Nagy     ShortMsg = formatv(
28225b9696bSDonát Nagy         "The shift '{0} << {1}' overflows the capacity of '{2}'",
28325b9696bSDonát Nagy         Left->getValue(), ConcreteRight->getValue(), LHSTy.getAsString());
28425b9696bSDonát Nagy     Msg = formatv(
28525b9696bSDonát Nagy         "The shift '{0} << {1}' is undefined {2}, so {3} bit{4} overflow{5}",
28625b9696bSDonát Nagy         Left->getValue(), ConcreteRight->getValue(), CapacityMsg, OverflownBits,
28725b9696bSDonát Nagy         pluralSuffix(OverflownBits), verbSuffix(OverflownBits));
28825b9696bSDonát Nagy   } else {
28925b9696bSDonát Nagy     ShortMsg = formatv("Left shift of '{0}' overflows the capacity of '{1}'",
29025b9696bSDonát Nagy                        Left->getValue(), LHSTy.getAsString());
29125b9696bSDonát Nagy     Msg = formatv(
29225b9696bSDonát Nagy         "Left shift of '{0}' is undefined {1}, so some bits overflow",
29325b9696bSDonát Nagy         Left->getValue(), CapacityMsg);
29425b9696bSDonát Nagy   }
29525b9696bSDonát Nagy 
29625b9696bSDonát Nagy   return createBugReport(ShortMsg, Msg);
29725b9696bSDonát Nagy }
29825b9696bSDonát Nagy 
29925b9696bSDonát Nagy void BitwiseShiftValidator::recordAssumption(OperandSide Side,
30025b9696bSDonát Nagy                                              BinaryOperator::Opcode Comparison,
30125b9696bSDonát Nagy                                              unsigned Limit) {
30225b9696bSDonát Nagy   switch (Comparison)  {
30325b9696bSDonát Nagy     case BO_GE:
30425b9696bSDonát Nagy       assert(Limit == 0);
30525b9696bSDonát Nagy       NonNegOperands |= (Side == OperandSide::Left ? NonNegLeft : NonNegRight);
30625b9696bSDonát Nagy       break;
30725b9696bSDonát Nagy     case BO_LT:
30825b9696bSDonát Nagy       assert(Side == OperandSide::Right);
30925b9696bSDonát Nagy       if (!UpperBoundBitCount || Limit < UpperBoundBitCount.value())
31025b9696bSDonát Nagy         UpperBoundBitCount = Limit;
31125b9696bSDonát Nagy       break;
31225b9696bSDonát Nagy     default:
31325b9696bSDonát Nagy       llvm_unreachable("this checker does not use other comparison operators");
31425b9696bSDonát Nagy   }
31525b9696bSDonát Nagy }
31625b9696bSDonát Nagy 
31725b9696bSDonát Nagy const NoteTag *BitwiseShiftValidator::createNoteTag() const {
31825b9696bSDonát Nagy   if (!NonNegOperands && !UpperBoundBitCount)
31925b9696bSDonát Nagy     return nullptr;
32025b9696bSDonát Nagy 
32125b9696bSDonát Nagy   SmallString<128> Buf;
32225b9696bSDonát Nagy   llvm::raw_svector_ostream Out(Buf);
32325b9696bSDonát Nagy   Out << "Assuming ";
32425b9696bSDonát Nagy   NoteTagTemplate Templ = NoteTagTemplates[NonNegOperands];
32525b9696bSDonát Nagy   Out << Templ.SignInfo;
32625b9696bSDonát Nagy   if (UpperBoundBitCount)
32725b9696bSDonát Nagy     Out << Templ.UpperBoundIntro << UpperBoundBitCount.value();
32825b9696bSDonát Nagy   const std::string Msg(Out.str());
32925b9696bSDonát Nagy 
33025b9696bSDonát Nagy   return Ctx.getNoteTag(Msg, /*isPrunable=*/true);
33125b9696bSDonát Nagy }
33225b9696bSDonát Nagy 
33325b9696bSDonát Nagy std::unique_ptr<PathSensitiveBugReport>
33425b9696bSDonát Nagy BitwiseShiftValidator::createBugReport(StringRef ShortMsg, StringRef Msg) const {
33525b9696bSDonát Nagy   ProgramStateRef State = Ctx.getState();
33625b9696bSDonát Nagy   if (ExplodedNode *ErrNode = Ctx.generateErrorNode(State)) {
33725b9696bSDonát Nagy     auto BR =
33825b9696bSDonát Nagy         std::make_unique<PathSensitiveBugReport>(BT, ShortMsg, Msg, ErrNode);
33925b9696bSDonát Nagy     bugreporter::trackExpressionValue(ErrNode, Op->getLHS(), *BR);
34025b9696bSDonát Nagy     bugreporter::trackExpressionValue(ErrNode, Op->getRHS(), *BR);
34125b9696bSDonát Nagy     return BR;
34225b9696bSDonát Nagy   }
34325b9696bSDonát Nagy   return nullptr;
34425b9696bSDonát Nagy }
34525b9696bSDonát Nagy } // anonymous namespace
34625b9696bSDonát Nagy 
34725b9696bSDonát Nagy class BitwiseShiftChecker : public Checker<check::PreStmt<BinaryOperator>> {
348e4c7ee3cSDonatNagyE   BugType BT{this, "Bitwise shift", "Suspicious operation"};
34925b9696bSDonát Nagy 
35025b9696bSDonát Nagy public:
35125b9696bSDonát Nagy   void checkPreStmt(const BinaryOperator *B, CheckerContext &Ctx) const {
35225b9696bSDonát Nagy     BinaryOperator::Opcode Op = B->getOpcode();
35325b9696bSDonát Nagy 
35425b9696bSDonát Nagy     if (Op != BO_Shl && Op != BO_Shr)
35525b9696bSDonát Nagy       return;
35625b9696bSDonát Nagy 
357e4c7ee3cSDonatNagyE     BitwiseShiftValidator(B, Ctx, BT, Pedantic).run();
35825b9696bSDonát Nagy   }
35925b9696bSDonát Nagy 
36025b9696bSDonát Nagy   bool Pedantic = false;
36125b9696bSDonát Nagy };
36225b9696bSDonát Nagy 
36325b9696bSDonát Nagy void ento::registerBitwiseShiftChecker(CheckerManager &Mgr) {
36425b9696bSDonát Nagy   auto *Chk = Mgr.registerChecker<BitwiseShiftChecker>();
36525b9696bSDonát Nagy   const AnalyzerOptions &Opts = Mgr.getAnalyzerOptions();
36625b9696bSDonát Nagy   Chk->Pedantic = Opts.getCheckerBooleanOption(Chk, "Pedantic");
36725b9696bSDonát Nagy }
36825b9696bSDonát Nagy 
36925b9696bSDonát Nagy bool ento::shouldRegisterBitwiseShiftChecker(const CheckerManager &mgr) {
37025b9696bSDonát Nagy   return true;
37125b9696bSDonát Nagy }
372