clang 20.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 Checker< check::PreStmt<BinaryOperator> > {
29 const BugType BT{this, "Division by zero"};
30 const BugType TaintBT{this, "Division by zero", categories::TaintedData};
31 void reportBug(StringRef Msg, ProgramStateRef StateZero,
32 CheckerContext &C) const;
33 void reportTaintBug(StringRef Msg, ProgramStateRef StateZero,
35 llvm::ArrayRef<SymbolRef> TaintedSyms) const;
36
37public:
38 void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
39};
40} // end anonymous namespace
41
42static const Expr *getDenomExpr(const ExplodedNode *N) {
43 const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
44 if (const auto *BE = dyn_cast<BinaryOperator>(S))
45 return BE->getRHS();
46 return nullptr;
47}
48
49void DivZeroChecker::reportBug(StringRef Msg, ProgramStateRef StateZero,
50 CheckerContext &C) const {
51 if (ExplodedNode *N = C.generateErrorNode(StateZero)) {
52 auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
54 C.emitReport(std::move(R));
55 }
56}
57
58void DivZeroChecker::reportTaintBug(
59 StringRef Msg, ProgramStateRef StateZero, CheckerContext &C,
60 llvm::ArrayRef<SymbolRef> TaintedSyms) const {
61 if (ExplodedNode *N = C.generateErrorNode(StateZero)) {
62 auto R = std::make_unique<PathSensitiveBugReport>(TaintBT, Msg, N);
64 for (auto Sym : TaintedSyms)
65 R->markInteresting(Sym);
66 C.emitReport(std::move(R));
67 }
68}
69
70void DivZeroChecker::checkPreStmt(const BinaryOperator *B,
71 CheckerContext &C) const {
73 if (Op != BO_Div &&
74 Op != BO_Rem &&
75 Op != BO_DivAssign &&
76 Op != BO_RemAssign)
77 return;
78
79 if (!B->getRHS()->getType()->isScalarType())
80 return;
81
82 SVal Denom = C.getSVal(B->getRHS());
83 std::optional<DefinedSVal> DV = Denom.getAs<DefinedSVal>();
84
85 // Divide-by-undefined handled in the generic checking for uses of
86 // undefined values.
87 if (!DV)
88 return;
89
90 // Check for divide by zero.
91 ConstraintManager &CM = C.getConstraintManager();
92 ProgramStateRef stateNotZero, stateZero;
93 std::tie(stateNotZero, stateZero) = CM.assumeDual(C.getState(), *DV);
94
95 if (!stateNotZero) {
96 assert(stateZero);
97 reportBug("Division by zero", stateZero, C);
98 return;
99 }
100
101 if ((stateNotZero && stateZero)) {
102 std::vector<SymbolRef> taintedSyms = getTaintedSymbols(C.getState(), *DV);
103 if (!taintedSyms.empty()) {
104 reportTaintBug("Division by a tainted value, possibly zero", stateZero, C,
105 taintedSyms);
106 return;
107 }
108 }
109
110 // If we get here, then the denom should not be zero. We abandon the implicit
111 // zero denom case for now.
112 C.addTransition(stateNotZero);
113}
114
115void ento::registerDivZeroChecker(CheckerManager &mgr) {
116 mgr.registerChecker<DivZeroChecker>();
117}
118
119bool ento::shouldRegisterDivZeroChecker(const CheckerManager &mgr) {
120 return true;
121}
static const Expr * getDenomExpr(const ExplodedNode *N)
A builtin binary operation expression such as "x + y" or "x <= y".
Definition: Expr.h:3860
Expr * getRHS() const
Definition: Expr.h:3912
Opcode getOpcode() const
Definition: Expr.h:3905
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:8418
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
The JSON file list parser is used to communicate input to InstallAPI.
BinaryOperatorKind