1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" |
15 | #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" |
16 | #include "clang/StaticAnalyzer/Core/Checker.h" |
17 | #include "clang/StaticAnalyzer/Core/CheckerManager.h" |
18 | #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" |
19 | |
20 | using namespace clang; |
21 | using namespace ento; |
22 | |
23 | namespace { |
24 | class DivZeroChecker : public Checker< check::PreStmt<BinaryOperator> > { |
25 | mutable std::unique_ptr<BuiltinBug> BT; |
26 | void reportBug(const char *Msg, ProgramStateRef StateZero, CheckerContext &C, |
27 | std::unique_ptr<BugReporterVisitor> Visitor = nullptr) const; |
28 | |
29 | public: |
30 | void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const; |
31 | }; |
32 | } |
33 | |
34 | static const Expr *getDenomExpr(const ExplodedNode *N) { |
35 | const Stmt *S = N->getLocationAs<PreStmt>()->getStmt(); |
36 | if (const auto *BE = dyn_cast<BinaryOperator>(S)) |
37 | return BE->getRHS(); |
38 | return nullptr; |
39 | } |
40 | |
41 | void DivZeroChecker::reportBug( |
42 | const char *Msg, ProgramStateRef StateZero, CheckerContext &C, |
43 | std::unique_ptr<BugReporterVisitor> Visitor) const { |
44 | if (ExplodedNode *N = C.generateErrorNode(StateZero)) { |
45 | if (!BT) |
46 | BT.reset(new BuiltinBug(this, "Division by zero")); |
47 | |
48 | auto R = llvm::make_unique<BugReport>(*BT, Msg, N); |
49 | R->addVisitor(std::move(Visitor)); |
50 | bugreporter::trackExpressionValue(N, getDenomExpr(N), *R); |
51 | C.emitReport(std::move(R)); |
52 | } |
53 | } |
54 | |
55 | void DivZeroChecker::checkPreStmt(const BinaryOperator *B, |
56 | CheckerContext &C) const { |
57 | BinaryOperator::Opcode Op = B->getOpcode(); |
58 | if (Op != BO_Div && |
59 | Op != BO_Rem && |
60 | Op != BO_DivAssign && |
61 | Op != BO_RemAssign) |
62 | return; |
63 | |
64 | if (!B->getRHS()->getType()->isScalarType()) |
65 | return; |
66 | |
67 | SVal Denom = C.getSVal(B->getRHS()); |
68 | Optional<DefinedSVal> DV = Denom.getAs<DefinedSVal>(); |
69 | |
70 | |
71 | |
72 | if (!DV) |
73 | return; |
74 | |
75 | |
76 | ConstraintManager &CM = C.getConstraintManager(); |
77 | ProgramStateRef stateNotZero, stateZero; |
78 | std::tie(stateNotZero, stateZero) = CM.assumeDual(C.getState(), *DV); |
79 | |
80 | if (!stateNotZero) { |
81 | assert(stateZero); |
82 | reportBug("Division by zero", stateZero, C); |
83 | return; |
84 | } |
85 | |
86 | bool TaintedD = C.getState()->isTainted(*DV); |
87 | if ((stateNotZero && stateZero && TaintedD)) { |
88 | reportBug("Division by a tainted value, possibly zero", stateZero, C, |
89 | llvm::make_unique<TaintBugVisitor>(*DV)); |
90 | return; |
91 | } |
92 | |
93 | |
94 | |
95 | C.addTransition(stateNotZero); |
96 | } |
97 | |
98 | void ento::registerDivZeroChecker(CheckerManager &mgr) { |
99 | mgr.registerChecker<DivZeroChecker>(); |
100 | } |
101 | |
102 | bool ento::shouldRegisterDivZeroChecker(const LangOptions &LO) { |
103 | return true; |
104 | } |
105 | |