1 //== DivZeroChecker.cpp - Division by zero checker --------------*- C++ -*--==//
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
7 //===----------------------------------------------------------------------===//
9 // This defines DivZeroChecker, a builtin check in ExprEngine that performs
10 // checks for division by zeros.
12 //===----------------------------------------------------------------------===//
14 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
15 #include "clang/StaticAnalyzer/Checkers/Taint.h"
16 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
17 #include "clang/StaticAnalyzer/Core/Checker.h"
18 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
19 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
22 using namespace clang
;
24 using namespace taint
;
27 class 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;
37 void checkPreStmt(const BinaryOperator
*B
, CheckerContext
&C
) const;
39 } // end anonymous namespace
41 static const Expr
*getDenomExpr(const ExplodedNode
*N
) {
42 const Stmt
*S
= N
->getLocationAs
<PreStmt
>()->getStmt();
43 if (const auto *BE
= dyn_cast
<BinaryOperator
>(S
))
48 void DivZeroChecker::reportBug(StringRef Msg
, ProgramStateRef StateZero
,
49 CheckerContext
&C
) const {
50 if (ExplodedNode
*N
= C
.generateErrorNode(StateZero
)) {
52 BT
.reset(new BugType(this, "Division by zero", categories::LogicError
));
54 auto R
= std::make_unique
<PathSensitiveBugReport
>(*BT
, Msg
, N
);
55 bugreporter::trackExpressionValue(N
, getDenomExpr(N
), *R
);
56 C
.emitReport(std::move(R
));
60 void DivZeroChecker::reportTaintBug(
61 StringRef Msg
, ProgramStateRef StateZero
, CheckerContext
&C
,
62 llvm::ArrayRef
<SymbolRef
> TaintedSyms
) const {
63 if (ExplodedNode
*N
= C
.generateErrorNode(StateZero
)) {
66 new BugType(this, "Division by zero", categories::TaintedData
));
68 auto R
= std::make_unique
<PathSensitiveBugReport
>(*TaintBT
, Msg
, N
);
69 bugreporter::trackExpressionValue(N
, getDenomExpr(N
), *R
);
70 for (auto Sym
: TaintedSyms
)
71 R
->markInteresting(Sym
);
72 C
.emitReport(std::move(R
));
76 void DivZeroChecker::checkPreStmt(const BinaryOperator
*B
,
77 CheckerContext
&C
) const {
78 BinaryOperator::Opcode Op
= B
->getOpcode();
85 if (!B
->getRHS()->getType()->isScalarType())
88 SVal Denom
= C
.getSVal(B
->getRHS());
89 std::optional
<DefinedSVal
> DV
= Denom
.getAs
<DefinedSVal
>();
91 // Divide-by-undefined handled in the generic checking for uses of
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
);
103 reportBug("Division by zero", stateZero
, C
);
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
,
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
);
121 void ento::registerDivZeroChecker(CheckerManager
&mgr
) {
122 mgr
.registerChecker
<DivZeroChecker
>();
125 bool ento::shouldRegisterDivZeroChecker(const CheckerManager
&mgr
) {