clang 18.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
20#include <optional>
21
22using namespace clang;
23using namespace ento;
24using namespace taint;
25
26namespace {
27class DivZeroChecker : public Checker< check::PreStmt<BinaryOperator> > {
28 mutable std::unique_ptr<BugType> BT;
29 mutable std::unique_ptr<BugType> TaintBT;
30 void reportBug(StringRef Msg, ProgramStateRef StateZero,
31 CheckerContext &C) const;
32 void reportTaintBug(StringRef Msg, ProgramStateRef StateZero,
34 llvm::ArrayRef<SymbolRef> TaintedSyms) const;
35
36public:
37 void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
38};
39} // end anonymous namespace
40
41static const Expr *getDenomExpr(const ExplodedNode *N) {
42 const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
43 if (const auto *BE = dyn_cast<BinaryOperator>(S))
44 return BE->getRHS();
45 return nullptr;
46}
47
48void DivZeroChecker::reportBug(StringRef Msg, ProgramStateRef StateZero,
49 CheckerContext &C) const {
50 if (ExplodedNode *N = C.generateErrorNode(StateZero)) {
51 if (!BT)
52 BT.reset(new BugType(this, "Division by zero", categories::LogicError));
53
54 auto R = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
56 C.emitReport(std::move(R));
57 }
58}
59
60void DivZeroChecker::reportTaintBug(
61 StringRef Msg, ProgramStateRef StateZero, CheckerContext &C,
62 llvm::ArrayRef<SymbolRef> TaintedSyms) const {
63 if (ExplodedNode *N = C.generateErrorNode(StateZero)) {
64 if (!TaintBT)
65 TaintBT.reset(
66 new BugType(this, "Division by zero", categories::TaintedData));
67
68 auto R = std::make_unique<PathSensitiveBugReport>(*TaintBT, Msg, N);
70 for (auto Sym : TaintedSyms)
71 R->markInteresting(Sym);
72 C.emitReport(std::move(R));
73 }
74}
75
76void DivZeroChecker::checkPreStmt(const BinaryOperator *B,
77 CheckerContext &C) const {
79 if (Op != BO_Div &&
80 Op != BO_Rem &&
81 Op != BO_DivAssign &&
82 Op != BO_RemAssign)
83 return;
84
85 if (!B->getRHS()->getType()->isScalarType())
86 return;
87
88 SVal Denom = C.getSVal(B->getRHS());
89 std::optional<DefinedSVal> DV = Denom.getAs<DefinedSVal>();
90
91 // Divide-by-undefined handled in the generic checking for uses of
92 // undefined values.
93 if (!DV)
94 return;
95
96 // Check for divide by zero.
97 ConstraintManager &CM = C.getConstraintManager();
98 ProgramStateRef stateNotZero, stateZero;
99 std::tie(stateNotZero, stateZero) = CM.assumeDual(C.getState(), *DV);
100
101 if (!stateNotZero) {
102 assert(stateZero);
103 reportBug("Division by zero", stateZero, C);
104 return;
105 }
106
107 if ((stateNotZero && stateZero)) {
108 std::vector<SymbolRef> taintedSyms = getTaintedSymbols(C.getState(), *DV);
109 if (!taintedSyms.empty()) {
110 reportTaintBug("Division by a tainted value, possibly zero", stateZero, C,
111 taintedSyms);
112 return;
113 }
114 }
115
116 // If we get here, then the denom should not be zero. We abandon the implicit
117 // zero denom case for now.
118 C.addTransition(stateNotZero);
119}
120
121void ento::registerDivZeroChecker(CheckerManager &mgr) {
122 mgr.registerChecker<DivZeroChecker>();
123}
124
125bool ento::shouldRegisterDivZeroChecker(const CheckerManager &mgr) {
126 return true;
127}
static const Expr * getDenomExpr(const ExplodedNode *N)
A builtin binary operation expression such as "x + y" or "x <= y".
Definition: Expr.h:3862
Expr * getRHS() const
Definition: Expr.h:3913
Opcode getOpcode() const
Definition: Expr.h:3906
This represents one expression.
Definition: Expr.h:110
QualType getType() const
Definition: Expr.h:142
Stmt - This represents one statement.
Definition: Stmt.h:84
bool isScalarType() const
Definition: Type.h:7439
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
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 &
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
Definition: SVals.h:55
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:86
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:169
BinaryOperatorKind