1 | //=== PointerSubChecker.cpp - Pointer subtraction 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 files defines PointerSubChecker, a builtin checker that checks for |
10 | // pointer subtractions on two pointers pointing to different memory chunks. |
11 | // This check corresponds to CWE-469. |
12 | // |
13 | //===----------------------------------------------------------------------===// |
14 | |
15 | #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.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" |
20 | |
21 | using namespace clang; |
22 | using namespace ento; |
23 | |
24 | namespace { |
25 | class PointerSubChecker |
26 | : public Checker< check::PreStmt<BinaryOperator> > { |
27 | mutable std::unique_ptr<BuiltinBug> BT; |
28 | |
29 | public: |
30 | void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const; |
31 | }; |
32 | } |
33 | |
34 | void PointerSubChecker::checkPreStmt(const BinaryOperator *B, |
35 | CheckerContext &C) const { |
36 | // When doing pointer subtraction, if the two pointers do not point to the |
37 | // same memory chunk, emit a warning. |
38 | if (B->getOpcode() != BO_Sub) |
39 | return; |
40 | |
41 | SVal LV = C.getSVal(B->getLHS()); |
42 | SVal RV = C.getSVal(B->getRHS()); |
43 | |
44 | const MemRegion *LR = LV.getAsRegion(); |
45 | const MemRegion *RR = RV.getAsRegion(); |
46 | |
47 | if (!(LR && RR)) |
48 | return; |
49 | |
50 | const MemRegion *BaseLR = LR->getBaseRegion(); |
51 | const MemRegion *BaseRR = RR->getBaseRegion(); |
52 | |
53 | if (BaseLR == BaseRR) |
54 | return; |
55 | |
56 | // Allow arithmetic on different symbolic regions. |
57 | if (isa<SymbolicRegion>(BaseLR) || isa<SymbolicRegion>(BaseRR)) |
58 | return; |
59 | |
60 | if (ExplodedNode *N = C.generateNonFatalErrorNode()) { |
61 | if (!BT) |
62 | BT.reset( |
63 | new BuiltinBug(this, "Pointer subtraction", |
64 | "Subtraction of two pointers that do not point to " |
65 | "the same memory chunk may cause incorrect result.")); |
66 | auto R = llvm::make_unique<BugReport>(*BT, BT->getDescription(), N); |
67 | R->addRange(B->getSourceRange()); |
68 | C.emitReport(std::move(R)); |
69 | } |
70 | } |
71 | |
72 | void ento::registerPointerSubChecker(CheckerManager &mgr) { |
73 | mgr.registerChecker<PointerSubChecker>(); |
74 | } |
75 | |
76 | bool ento::shouldRegisterPointerSubChecker(const LangOptions &LO) { |
77 | return true; |
78 | } |
79 |