1d99bd55aSTed Kremenek //=== PointerSubChecker.cpp - Pointer subtraction checker ------*- C++ -*--===//
2d99bd55aSTed Kremenek //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d99bd55aSTed Kremenek //
7d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
8d99bd55aSTed Kremenek //
9d99bd55aSTed Kremenek // This files defines PointerSubChecker, a builtin checker that checks for
10d99bd55aSTed Kremenek // pointer subtractions on two pointers pointing to different memory chunks.
11d99bd55aSTed Kremenek // This check corresponds to CWE-469.
12d99bd55aSTed Kremenek //
13d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
14d99bd55aSTed Kremenek
1576a21502SKristof Umann #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
163a02247dSChandler Carruth #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
176a5674ffSArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/Checker.h"
18507ff53eSArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/CheckerManager.h"
19dff865d1SArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20d99bd55aSTed Kremenek
21d99bd55aSTed Kremenek using namespace clang;
22d99bd55aSTed Kremenek using namespace ento;
23d99bd55aSTed Kremenek
24d99bd55aSTed Kremenek namespace {
25d99bd55aSTed Kremenek class PointerSubChecker
266a5674ffSArgyrios Kyrtzidis : public Checker< check::PreStmt<BinaryOperator> > {
27b8984329SAhmed Charles mutable std::unique_ptr<BuiltinBug> BT;
28dff865d1SArgyrios Kyrtzidis
29d99bd55aSTed Kremenek public:
30dff865d1SArgyrios Kyrtzidis void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
31d99bd55aSTed Kremenek };
32d99bd55aSTed Kremenek }
33d99bd55aSTed Kremenek
checkPreStmt(const BinaryOperator * B,CheckerContext & C) const34dff865d1SArgyrios Kyrtzidis void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
35dff865d1SArgyrios Kyrtzidis CheckerContext &C) const {
36d99bd55aSTed Kremenek // When doing pointer subtraction, if the two pointers do not point to the
37d99bd55aSTed Kremenek // same memory chunk, emit a warning.
38d99bd55aSTed Kremenek if (B->getOpcode() != BO_Sub)
39d99bd55aSTed Kremenek return;
40d99bd55aSTed Kremenek
41d703ec94SGeorge Karpenkov SVal LV = C.getSVal(B->getLHS());
42d703ec94SGeorge Karpenkov SVal RV = C.getSVal(B->getRHS());
43d99bd55aSTed Kremenek
44d99bd55aSTed Kremenek const MemRegion *LR = LV.getAsRegion();
45d99bd55aSTed Kremenek const MemRegion *RR = RV.getAsRegion();
46d99bd55aSTed Kremenek
47d99bd55aSTed Kremenek if (!(LR && RR))
48d99bd55aSTed Kremenek return;
49d99bd55aSTed Kremenek
50d99bd55aSTed Kremenek const MemRegion *BaseLR = LR->getBaseRegion();
51d99bd55aSTed Kremenek const MemRegion *BaseRR = RR->getBaseRegion();
52d99bd55aSTed Kremenek
53d99bd55aSTed Kremenek if (BaseLR == BaseRR)
54d99bd55aSTed Kremenek return;
55d99bd55aSTed Kremenek
56d99bd55aSTed Kremenek // Allow arithmetic on different symbolic regions.
57d99bd55aSTed Kremenek if (isa<SymbolicRegion>(BaseLR) || isa<SymbolicRegion>(BaseRR))
58d99bd55aSTed Kremenek return;
59d99bd55aSTed Kremenek
60e39bd407SDevin Coughlin if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
61d99bd55aSTed Kremenek if (!BT)
624aca9b1cSAlexander Kornienko BT.reset(
634aca9b1cSAlexander Kornienko new BuiltinBug(this, "Pointer subtraction",
64d99bd55aSTed Kremenek "Subtraction of two pointers that do not point to "
65dff865d1SArgyrios Kyrtzidis "the same memory chunk may cause incorrect result."));
662f169e7cSArtem Dergachev auto R =
672f169e7cSArtem Dergachev std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
68d99bd55aSTed Kremenek R->addRange(B->getSourceRange());
698d3a7a56SAaron Ballman C.emitReport(std::move(R));
70d99bd55aSTed Kremenek }
71d99bd55aSTed Kremenek }
72d99bd55aSTed Kremenek
registerPointerSubChecker(CheckerManager & mgr)73507ff53eSArgyrios Kyrtzidis void ento::registerPointerSubChecker(CheckerManager &mgr) {
74dff865d1SArgyrios Kyrtzidis mgr.registerChecker<PointerSubChecker>();
75507ff53eSArgyrios Kyrtzidis }
76058a7a45SKristof Umann
shouldRegisterPointerSubChecker(const CheckerManager & mgr)77*bda3dd0dSKirstóf Umann bool ento::shouldRegisterPointerSubChecker(const CheckerManager &mgr) {
78058a7a45SKristof Umann return true;
79058a7a45SKristof Umann }
80