1*0b57cec5SDimitry Andric //=== PointerSubChecker.cpp - Pointer subtraction checker ------*- C++ -*--===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric // This files defines PointerSubChecker, a builtin checker that checks for
10*0b57cec5SDimitry Andric // pointer subtractions on two pointers pointing to different memory chunks.
11*0b57cec5SDimitry Andric // This check corresponds to CWE-469.
12*0b57cec5SDimitry Andric //
13*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
14*0b57cec5SDimitry Andric
15*0b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
16*0b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
17*0b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
18*0b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h"
19*0b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20*0b57cec5SDimitry Andric
21*0b57cec5SDimitry Andric using namespace clang;
22*0b57cec5SDimitry Andric using namespace ento;
23*0b57cec5SDimitry Andric
24*0b57cec5SDimitry Andric namespace {
25*0b57cec5SDimitry Andric class PointerSubChecker
26*0b57cec5SDimitry Andric : public Checker< check::PreStmt<BinaryOperator> > {
27*0b57cec5SDimitry Andric mutable std::unique_ptr<BuiltinBug> BT;
28*0b57cec5SDimitry Andric
29*0b57cec5SDimitry Andric public:
30*0b57cec5SDimitry Andric void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
31*0b57cec5SDimitry Andric };
32*0b57cec5SDimitry Andric }
33*0b57cec5SDimitry Andric
checkPreStmt(const BinaryOperator * B,CheckerContext & C) const34*0b57cec5SDimitry Andric void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
35*0b57cec5SDimitry Andric CheckerContext &C) const {
36*0b57cec5SDimitry Andric // When doing pointer subtraction, if the two pointers do not point to the
37*0b57cec5SDimitry Andric // same memory chunk, emit a warning.
38*0b57cec5SDimitry Andric if (B->getOpcode() != BO_Sub)
39*0b57cec5SDimitry Andric return;
40*0b57cec5SDimitry Andric
41*0b57cec5SDimitry Andric SVal LV = C.getSVal(B->getLHS());
42*0b57cec5SDimitry Andric SVal RV = C.getSVal(B->getRHS());
43*0b57cec5SDimitry Andric
44*0b57cec5SDimitry Andric const MemRegion *LR = LV.getAsRegion();
45*0b57cec5SDimitry Andric const MemRegion *RR = RV.getAsRegion();
46*0b57cec5SDimitry Andric
47*0b57cec5SDimitry Andric if (!(LR && RR))
48*0b57cec5SDimitry Andric return;
49*0b57cec5SDimitry Andric
50*0b57cec5SDimitry Andric const MemRegion *BaseLR = LR->getBaseRegion();
51*0b57cec5SDimitry Andric const MemRegion *BaseRR = RR->getBaseRegion();
52*0b57cec5SDimitry Andric
53*0b57cec5SDimitry Andric if (BaseLR == BaseRR)
54*0b57cec5SDimitry Andric return;
55*0b57cec5SDimitry Andric
56*0b57cec5SDimitry Andric // Allow arithmetic on different symbolic regions.
57*0b57cec5SDimitry Andric if (isa<SymbolicRegion>(BaseLR) || isa<SymbolicRegion>(BaseRR))
58*0b57cec5SDimitry Andric return;
59*0b57cec5SDimitry Andric
60*0b57cec5SDimitry Andric if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
61*0b57cec5SDimitry Andric if (!BT)
62*0b57cec5SDimitry Andric BT.reset(
63*0b57cec5SDimitry Andric new BuiltinBug(this, "Pointer subtraction",
64*0b57cec5SDimitry Andric "Subtraction of two pointers that do not point to "
65*0b57cec5SDimitry Andric "the same memory chunk may cause incorrect result."));
66*0b57cec5SDimitry Andric auto R =
67*0b57cec5SDimitry Andric std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
68*0b57cec5SDimitry Andric R->addRange(B->getSourceRange());
69*0b57cec5SDimitry Andric C.emitReport(std::move(R));
70*0b57cec5SDimitry Andric }
71*0b57cec5SDimitry Andric }
72*0b57cec5SDimitry Andric
registerPointerSubChecker(CheckerManager & mgr)73*0b57cec5SDimitry Andric void ento::registerPointerSubChecker(CheckerManager &mgr) {
74*0b57cec5SDimitry Andric mgr.registerChecker<PointerSubChecker>();
75*0b57cec5SDimitry Andric }
76*0b57cec5SDimitry Andric
shouldRegisterPointerSubChecker(const CheckerManager & mgr)77*0b57cec5SDimitry Andric bool ento::shouldRegisterPointerSubChecker(const CheckerManager &mgr) {
78*0b57cec5SDimitry Andric return true;
79 }
80