10b57cec5SDimitry Andric //=== PointerSubChecker.cpp - Pointer subtraction checker ------*- C++ -*--===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This files defines PointerSubChecker, a builtin checker that checks for
100b57cec5SDimitry Andric // pointer subtractions on two pointers pointing to different memory chunks.
110b57cec5SDimitry Andric // This check corresponds to CWE-469.
120b57cec5SDimitry Andric //
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric
150b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
160b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
170b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
180b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h"
190b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20c9157d92SDimitry Andric #include "llvm/ADT/StringRef.h"
210b57cec5SDimitry Andric
220b57cec5SDimitry Andric using namespace clang;
230b57cec5SDimitry Andric using namespace ento;
240b57cec5SDimitry Andric
250b57cec5SDimitry Andric namespace {
260b57cec5SDimitry Andric class PointerSubChecker
270b57cec5SDimitry Andric : public Checker< check::PreStmt<BinaryOperator> > {
28*de8261c4SDimitry Andric const BugType BT{this, "Pointer subtraction"};
290b57cec5SDimitry Andric
300b57cec5SDimitry Andric public:
310b57cec5SDimitry Andric void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
320b57cec5SDimitry Andric };
330b57cec5SDimitry Andric }
340b57cec5SDimitry Andric
checkPreStmt(const BinaryOperator * B,CheckerContext & C) const350b57cec5SDimitry Andric void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
360b57cec5SDimitry Andric CheckerContext &C) const {
370b57cec5SDimitry Andric // When doing pointer subtraction, if the two pointers do not point to the
380b57cec5SDimitry Andric // same memory chunk, emit a warning.
390b57cec5SDimitry Andric if (B->getOpcode() != BO_Sub)
400b57cec5SDimitry Andric return;
410b57cec5SDimitry Andric
420b57cec5SDimitry Andric SVal LV = C.getSVal(B->getLHS());
430b57cec5SDimitry Andric SVal RV = C.getSVal(B->getRHS());
440b57cec5SDimitry Andric
450b57cec5SDimitry Andric const MemRegion *LR = LV.getAsRegion();
460b57cec5SDimitry Andric const MemRegion *RR = RV.getAsRegion();
470b57cec5SDimitry Andric
480b57cec5SDimitry Andric if (!(LR && RR))
490b57cec5SDimitry Andric return;
500b57cec5SDimitry Andric
510b57cec5SDimitry Andric const MemRegion *BaseLR = LR->getBaseRegion();
520b57cec5SDimitry Andric const MemRegion *BaseRR = RR->getBaseRegion();
530b57cec5SDimitry Andric
540b57cec5SDimitry Andric if (BaseLR == BaseRR)
550b57cec5SDimitry Andric return;
560b57cec5SDimitry Andric
570b57cec5SDimitry Andric // Allow arithmetic on different symbolic regions.
580b57cec5SDimitry Andric if (isa<SymbolicRegion>(BaseLR) || isa<SymbolicRegion>(BaseRR))
590b57cec5SDimitry Andric return;
600b57cec5SDimitry Andric
610b57cec5SDimitry Andric if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
62c9157d92SDimitry Andric constexpr llvm::StringLiteral Msg =
63c9157d92SDimitry Andric "Subtraction of two pointers that do not point to the same memory "
64c9157d92SDimitry Andric "chunk may cause incorrect result.";
65*de8261c4SDimitry Andric auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
660b57cec5SDimitry Andric R->addRange(B->getSourceRange());
670b57cec5SDimitry Andric C.emitReport(std::move(R));
680b57cec5SDimitry Andric }
690b57cec5SDimitry Andric }
700b57cec5SDimitry Andric
registerPointerSubChecker(CheckerManager & mgr)710b57cec5SDimitry Andric void ento::registerPointerSubChecker(CheckerManager &mgr) {
720b57cec5SDimitry Andric mgr.registerChecker<PointerSubChecker>();
730b57cec5SDimitry Andric }
740b57cec5SDimitry Andric
shouldRegisterPointerSubChecker(const CheckerManager & mgr)755ffd83dbSDimitry Andric bool ento::shouldRegisterPointerSubChecker(const CheckerManager &mgr) {
760b57cec5SDimitry Andric return true;
770b57cec5SDimitry Andric }
78