blob: 33e8fcd8af7bb351d16c42c81f7a0b91412e6c14 [file] [log] [blame]
Zhongxing Xub1c24722009-10-31 10:02:37 +00001//== DivZeroChecker.cpp - Division by zero checker --------------*- C++ -*--==//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Zhongxing Xub1c24722009-10-31 10:02:37 +00006//
7//===----------------------------------------------------------------------===//
8//
Argyrios Kyrtzidis1696f502010-12-22 18:53:44 +00009// This defines DivZeroChecker, a builtin check in ExprEngine that performs
Zhongxing Xub1c24722009-10-31 10:02:37 +000010// checks for division by zeros.
11//
12//===----------------------------------------------------------------------===//
13
Artem Dergachev44551cf2019-03-29 22:49:30 +000014#include "Taint.h"
Kristof Umann76a21502018-12-15 16:23:51 +000015#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000016#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +000017#include "clang/StaticAnalyzer/Core/Checker.h"
Argyrios Kyrtzidisae468f72011-02-28 01:27:50 +000018#include "clang/StaticAnalyzer/Core/CheckerManager.h"
19#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
Zhongxing Xub1c24722009-10-31 10:02:37 +000020
21using namespace clang;
Ted Kremenek98857c92010-12-23 07:20:52 +000022using namespace ento;
Artem Dergachev44551cf2019-03-29 22:49:30 +000023using namespace taint;
Zhongxing Xub1c24722009-10-31 10:02:37 +000024
Ted Kremenek53a70c02009-11-06 20:47:51 +000025namespace {
Argyrios Kyrtzidis6a5674f2011-03-01 01:16:21 +000026class DivZeroChecker : public Checker< check::PreStmt<BinaryOperator> > {
Ahmed Charlesb8984322014-03-07 20:03:18 +000027 mutable std::unique_ptr<BuiltinBug> BT;
Henry Wonge14e5912018-05-02 12:11:22 +000028 void reportBug(const char *Msg, ProgramStateRef StateZero, CheckerContext &C,
29 std::unique_ptr<BugReporterVisitor> Visitor = nullptr) const;
30
Ted Kremenek53a70c02009-11-06 20:47:51 +000031public:
Argyrios Kyrtzidisae468f72011-02-28 01:27:50 +000032 void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
Ted Kremenek3a0678e2015-09-08 03:50:52 +000033};
Ted Kremenek53a70c02009-11-06 20:47:51 +000034} // end anonymous namespace
35
George Karpenkovb2cf0062018-10-23 18:24:53 +000036static const Expr *getDenomExpr(const ExplodedNode *N) {
37 const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
38 if (const auto *BE = dyn_cast<BinaryOperator>(S))
39 return BE->getRHS();
40 return nullptr;
41}
42
Henry Wonge14e5912018-05-02 12:11:22 +000043void DivZeroChecker::reportBug(
44 const char *Msg, ProgramStateRef StateZero, CheckerContext &C,
45 std::unique_ptr<BugReporterVisitor> Visitor) const {
Devin Coughline39bd402015-09-16 22:03:05 +000046 if (ExplodedNode *N = C.generateErrorNode(StateZero)) {
Anna Zaks8298af82012-01-20 20:28:31 +000047 if (!BT)
Alexander Kornienko4aca9b12014-02-11 21:49:21 +000048 BT.reset(new BuiltinBug(this, "Division by zero"));
Anna Zaks8298af82012-01-20 20:28:31 +000049
Aaron Ballman8d3a7a52015-06-23 13:15:32 +000050 auto R = llvm::make_unique<BugReport>(*BT, Msg, N);
Henry Wonge14e5912018-05-02 12:11:22 +000051 R->addVisitor(std::move(Visitor));
George Karpenkovb2cf0062018-10-23 18:24:53 +000052 bugreporter::trackExpressionValue(N, getDenomExpr(N), *R);
Aaron Ballman8d3a7a52015-06-23 13:15:32 +000053 C.emitReport(std::move(R));
Anna Zaks8298af82012-01-20 20:28:31 +000054 }
55}
56
Argyrios Kyrtzidisae468f72011-02-28 01:27:50 +000057void DivZeroChecker::checkPreStmt(const BinaryOperator *B,
58 CheckerContext &C) const {
Zhongxing Xub1c24722009-10-31 10:02:37 +000059 BinaryOperator::Opcode Op = B->getOpcode();
John McCalle3027922010-08-25 11:45:40 +000060 if (Op != BO_Div &&
61 Op != BO_Rem &&
62 Op != BO_DivAssign &&
63 Op != BO_RemAssign)
Zhongxing Xub1c24722009-10-31 10:02:37 +000064 return;
65
Anna Zaks8698dd62012-07-10 16:27:55 +000066 if (!B->getRHS()->getType()->isScalarType())
Zhongxing Xub1c24722009-10-31 10:02:37 +000067 return;
68
George Karpenkovd703ec92018-01-17 20:27:29 +000069 SVal Denom = C.getSVal(B->getRHS());
David Blaikie05785d12013-02-20 22:23:23 +000070 Optional<DefinedSVal> DV = Denom.getAs<DefinedSVal>();
Zhongxing Xub1c24722009-10-31 10:02:37 +000071
72 // Divide-by-undefined handled in the generic checking for uses of
73 // undefined values.
74 if (!DV)
75 return;
76
77 // Check for divide by zero.
78 ConstraintManager &CM = C.getConstraintManager();
Ted Kremenek49b1e382012-01-26 21:29:00 +000079 ProgramStateRef stateNotZero, stateZero;
Benjamin Kramer867ea1d2014-03-02 13:01:17 +000080 std::tie(stateNotZero, stateZero) = CM.assumeDual(C.getState(), *DV);
Zhongxing Xub1c24722009-10-31 10:02:37 +000081
Anna Zaks0d580332011-11-08 19:56:35 +000082 if (!stateNotZero) {
83 assert(stateZero);
Anna Zaks8298af82012-01-20 20:28:31 +000084 reportBug("Division by zero", stateZero, C);
85 return;
86 }
Zhongxing Xub1c24722009-10-31 10:02:37 +000087
Artem Dergachev44551cf2019-03-29 22:49:30 +000088 bool TaintedD = isTainted(C.getState(), *DV);
Anna Zaks8298af82012-01-20 20:28:31 +000089 if ((stateNotZero && stateZero && TaintedD)) {
Henry Wonge14e5912018-05-02 12:11:22 +000090 reportBug("Division by a tainted value, possibly zero", stateZero, C,
Artem Dergachev44551cf2019-03-29 22:49:30 +000091 llvm::make_unique<taint::TaintBugVisitor>(*DV));
Zhongxing Xub1c24722009-10-31 10:02:37 +000092 return;
93 }
94
95 // If we get here, then the denom should not be zero. We abandon the implicit
96 // zero denom case for now.
Anna Zaksda4c8d62011-10-26 21:06:34 +000097 C.addTransition(stateNotZero);
Zhongxing Xub1c24722009-10-31 10:02:37 +000098}
Argyrios Kyrtzidisae468f72011-02-28 01:27:50 +000099
100void ento::registerDivZeroChecker(CheckerManager &mgr) {
101 mgr.registerChecker<DivZeroChecker>();
102}
Kristof Umann058a7a42019-01-26 14:23:08 +0000103
104bool ento::shouldRegisterDivZeroChecker(const LangOptions &LO) {
105 return true;
106}