clang 22.0.0git
DivZeroChecker.cpp
Go to the documentation of this file.
1//== DivZeroChecker.cpp - Division by zero checker --------------*- C++ -*--==//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This defines DivZeroChecker, a builtin check in ExprEngine that performs
10// checks for division by zeros.
11//
12//===----------------------------------------------------------------------===//
13
21#include <optional>
22
23using namespace clang;
24using namespace ento;
25using namespace taint;
26
27namespace {
28class DivZeroChecker : public CheckerFamily<check::PreStmt<BinaryOperator>> {
29 void reportBug(StringRef Msg, ProgramStateRef StateZero,
30 CheckerContext &C) const;
31 void reportTaintBug(StringRef Msg, ProgramStateRef StateZero,
32 CheckerContext &C,
33 llvm::ArrayRef<SymbolRef> TaintedSyms) const;
34
35public:
36 /// This checker family implements two user-facing checker parts.
37 CheckerFrontendWithBugType DivideZeroChecker{"Division by zero"};
38 CheckerFrontendWithBugType TaintedDivChecker{"Division by zero",
40
41 void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
42
43 /// Identifies this checker family for debugging purposes.
44 StringRef getDebugTag() const override { return "DivZeroChecker"; }
45};
46} // end anonymous namespace
47
48static const Expr *getDenomExpr(const ExplodedNode *N) {
49 const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
50 if (const auto *BE = dyn_cast<BinaryOperator>(S))
51 return BE->getRHS();
52 return nullptr;
53}
54
55void DivZeroChecker::reportBug(StringRef Msg, ProgramStateRef StateZero,
56 CheckerContext &C) const {
57 if (!DivideZeroChecker.isEnabled())
58 return;
59 if (ExplodedNode *N = C.generateErrorNode(StateZero)) {
60 auto R =
61 std::make_unique<PathSensitiveBugReport>(DivideZeroChecker, Msg, N);
63 C.emitReport(std::move(R));
64 }
65}
66
67void DivZeroChecker::reportTaintBug(
68 StringRef Msg, ProgramStateRef StateZero, CheckerContext &C,
69 llvm::ArrayRef<SymbolRef> TaintedSyms) const {
70 if (!TaintedDivChecker.isEnabled())
71 return;
72 if (ExplodedNode *N = C.generateErrorNode(StateZero)) {
73 auto R =
74 std::make_unique<PathSensitiveBugReport>(TaintedDivChecker, Msg, N);
76 for (auto Sym : TaintedSyms)
77 R->markInteresting(Sym);
78 C.emitReport(std::move(R));
79 }
80}
81
82void DivZeroChecker::checkPreStmt(const BinaryOperator *B,
83 CheckerContext &C) const {
85 if (Op != BO_Div &&
86 Op != BO_Rem &&
87 Op != BO_DivAssign &&
88 Op != BO_RemAssign)
89 return;
90
91 if (!B->getRHS()->getType()->isScalarType())
92 return;
93
94 SVal Denom = C.getSVal(B->getRHS());
95 std::optional<DefinedSVal> DV = Denom.getAs<DefinedSVal>();
96
97 // Divide-by-undefined handled in the generic checking for uses of
98 // undefined values.
99 if (!DV)
100 return;
101
102 // Check for divide by zero.
103 ConstraintManager &CM = C.getConstraintManager();
104 ProgramStateRef stateNotZero, stateZero;
105 std::tie(stateNotZero, stateZero) = CM.assumeDual(C.getState(), *DV);
106
107 if (!stateNotZero) {
108 assert(stateZero);
109 reportBug("Division by zero", stateZero, C);
110 return;
111 }
112
113 if ((stateNotZero && stateZero)) {
114 std::vector<SymbolRef> taintedSyms = getTaintedSymbols(C.getState(), *DV);
115 if (!taintedSyms.empty()) {
116 reportTaintBug("Division by a tainted value, possibly zero", stateZero, C,
117 taintedSyms);
118 // Fallthrough to continue analysis in case of non-zero denominator.
119 }
120 }
121
122 // If we get here, then the denom should not be zero. We abandon the implicit
123 // zero denom case for now.
124 C.addTransition(stateNotZero);
125}
126
127void ento::registerDivZeroChecker(CheckerManager &Mgr) {
128 Mgr.getChecker<DivZeroChecker>()->DivideZeroChecker.enable(Mgr);
129}
130
131bool ento::shouldRegisterDivZeroChecker(const CheckerManager &) { return true; }
132
133void ento::registerTaintedDivChecker(CheckerManager &Mgr) {
134 Mgr.getChecker<DivZeroChecker>()->TaintedDivChecker.enable(Mgr);
135}
136
137bool ento::shouldRegisterTaintedDivChecker(const CheckerManager &) {
138 return true;
139}
static const Expr * getDenomExpr(const ExplodedNode *N)
Expr * getRHS() const
Definition Expr.h:4024
Opcode getOpcode() const
Definition Expr.h:4017
BinaryOperatorKind Opcode
Definition Expr.h:3977
This represents one expression.
Definition Expr.h:112
QualType getType() const
Definition Expr.h:144
Stmt - This represents one statement.
Definition Stmt.h:85
bool isScalarType() const
Definition TypeBase.h:8980
Checker families (where a single backend class implements multiple related frontends) should derive f...
Definition Checker.h:584
CHECKER * getChecker(AT &&...Args)
If the the singleton instance of a checker class is not yet constructed, then construct it (with the ...
ProgramStatePair assumeDual(ProgramStateRef State, DefinedSVal Cond)
Returns a pair of states (StTrue, StFalse) where the given condition is assumed to be true or false,...
std::optional< T > getLocationAs() const &
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
Definition SVals.h:87
bool trackExpressionValue(const ExplodedNode *N, const Expr *E, PathSensitiveBugReport &R, TrackingOptions Opts={})
Attempts to add visitors to track expression value back to its point of origin.
std::vector< SymbolRef > getTaintedSymbols(ProgramStateRef State, const Stmt *S, const LocationContext *LCtx, TaintTagType Kind=TaintTagGeneric)
Returns the tainted Symbols for a given Statement and state.
Definition Taint.cpp:170
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
The JSON file list parser is used to communicate input to InstallAPI.