xref: /minix3/external/bsd/llvm/dist/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1f4a2713aSLionel Sambuc //== DivZeroChecker.cpp - Division by zero checker --------------*- C++ -*--==//
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc //                     The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc //
10f4a2713aSLionel Sambuc // This defines DivZeroChecker, a builtin check in ExprEngine that performs
11f4a2713aSLionel Sambuc // checks for division by zeros.
12f4a2713aSLionel Sambuc //
13f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
14f4a2713aSLionel Sambuc 
15f4a2713aSLionel Sambuc #include "ClangSACheckers.h"
16f4a2713aSLionel Sambuc #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
17f4a2713aSLionel Sambuc #include "clang/StaticAnalyzer/Core/Checker.h"
18f4a2713aSLionel Sambuc #include "clang/StaticAnalyzer/Core/CheckerManager.h"
19f4a2713aSLionel Sambuc #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20f4a2713aSLionel Sambuc 
21f4a2713aSLionel Sambuc using namespace clang;
22f4a2713aSLionel Sambuc using namespace ento;
23f4a2713aSLionel Sambuc 
24f4a2713aSLionel Sambuc namespace {
25f4a2713aSLionel Sambuc class DivZeroChecker : public Checker< check::PreStmt<BinaryOperator> > {
26*0a6a1f1dSLionel Sambuc   mutable std::unique_ptr<BuiltinBug> BT;
27f4a2713aSLionel Sambuc   void reportBug(const char *Msg,
28f4a2713aSLionel Sambuc                  ProgramStateRef StateZero,
29f4a2713aSLionel Sambuc                  CheckerContext &C) const ;
30f4a2713aSLionel Sambuc public:
31f4a2713aSLionel Sambuc   void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
32f4a2713aSLionel Sambuc };
33f4a2713aSLionel Sambuc } // end anonymous namespace
34f4a2713aSLionel Sambuc 
reportBug(const char * Msg,ProgramStateRef StateZero,CheckerContext & C) const35f4a2713aSLionel Sambuc void DivZeroChecker::reportBug(const char *Msg,
36f4a2713aSLionel Sambuc                                ProgramStateRef StateZero,
37f4a2713aSLionel Sambuc                                CheckerContext &C) const {
38f4a2713aSLionel Sambuc   if (ExplodedNode *N = C.generateSink(StateZero)) {
39f4a2713aSLionel Sambuc     if (!BT)
40*0a6a1f1dSLionel Sambuc       BT.reset(new BuiltinBug(this, "Division by zero"));
41f4a2713aSLionel Sambuc 
42f4a2713aSLionel Sambuc     BugReport *R = new BugReport(*BT, Msg, N);
43f4a2713aSLionel Sambuc     bugreporter::trackNullOrUndefValue(N, bugreporter::GetDenomExpr(N), *R);
44f4a2713aSLionel Sambuc     C.emitReport(R);
45f4a2713aSLionel Sambuc   }
46f4a2713aSLionel Sambuc }
47f4a2713aSLionel Sambuc 
checkPreStmt(const BinaryOperator * B,CheckerContext & C) const48f4a2713aSLionel Sambuc void DivZeroChecker::checkPreStmt(const BinaryOperator *B,
49f4a2713aSLionel Sambuc                                   CheckerContext &C) const {
50f4a2713aSLionel Sambuc   BinaryOperator::Opcode Op = B->getOpcode();
51f4a2713aSLionel Sambuc   if (Op != BO_Div &&
52f4a2713aSLionel Sambuc       Op != BO_Rem &&
53f4a2713aSLionel Sambuc       Op != BO_DivAssign &&
54f4a2713aSLionel Sambuc       Op != BO_RemAssign)
55f4a2713aSLionel Sambuc     return;
56f4a2713aSLionel Sambuc 
57f4a2713aSLionel Sambuc   if (!B->getRHS()->getType()->isScalarType())
58f4a2713aSLionel Sambuc     return;
59f4a2713aSLionel Sambuc 
60f4a2713aSLionel Sambuc   SVal Denom = C.getState()->getSVal(B->getRHS(), C.getLocationContext());
61f4a2713aSLionel Sambuc   Optional<DefinedSVal> DV = Denom.getAs<DefinedSVal>();
62f4a2713aSLionel Sambuc 
63f4a2713aSLionel Sambuc   // Divide-by-undefined handled in the generic checking for uses of
64f4a2713aSLionel Sambuc   // undefined values.
65f4a2713aSLionel Sambuc   if (!DV)
66f4a2713aSLionel Sambuc     return;
67f4a2713aSLionel Sambuc 
68f4a2713aSLionel Sambuc   // Check for divide by zero.
69f4a2713aSLionel Sambuc   ConstraintManager &CM = C.getConstraintManager();
70f4a2713aSLionel Sambuc   ProgramStateRef stateNotZero, stateZero;
71*0a6a1f1dSLionel Sambuc   std::tie(stateNotZero, stateZero) = CM.assumeDual(C.getState(), *DV);
72f4a2713aSLionel Sambuc 
73f4a2713aSLionel Sambuc   if (!stateNotZero) {
74f4a2713aSLionel Sambuc     assert(stateZero);
75f4a2713aSLionel Sambuc     reportBug("Division by zero", stateZero, C);
76f4a2713aSLionel Sambuc     return;
77f4a2713aSLionel Sambuc   }
78f4a2713aSLionel Sambuc 
79f4a2713aSLionel Sambuc   bool TaintedD = C.getState()->isTainted(*DV);
80f4a2713aSLionel Sambuc   if ((stateNotZero && stateZero && TaintedD)) {
81f4a2713aSLionel Sambuc     reportBug("Division by a tainted value, possibly zero", stateZero, C);
82f4a2713aSLionel Sambuc     return;
83f4a2713aSLionel Sambuc   }
84f4a2713aSLionel Sambuc 
85f4a2713aSLionel Sambuc   // If we get here, then the denom should not be zero. We abandon the implicit
86f4a2713aSLionel Sambuc   // zero denom case for now.
87f4a2713aSLionel Sambuc   C.addTransition(stateNotZero);
88f4a2713aSLionel Sambuc }
89f4a2713aSLionel Sambuc 
registerDivZeroChecker(CheckerManager & mgr)90f4a2713aSLionel Sambuc void ento::registerDivZeroChecker(CheckerManager &mgr) {
91f4a2713aSLionel Sambuc   mgr.registerChecker<DivZeroChecker>();
92f4a2713aSLionel Sambuc }
93