brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.2 KiB · 14004b8 Raw
125 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This files defines PointerSubChecker, a builtin checker that checks for10// 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#include "llvm/ADT/StringRef.h"21#include "llvm/Support/FormatVariadic.h"22 23using namespace clang;24using namespace ento;25 26namespace {27class PointerSubChecker28  : public Checker< check::PreStmt<BinaryOperator> > {29  const BugType BT{this, "Pointer subtraction"};30  const llvm::StringLiteral Msg_MemRegionDifferent =31      "Subtraction of two pointers that do not point into the same array "32      "is undefined behavior.";33 34public:35  void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;36};37}38 39void PointerSubChecker::checkPreStmt(const BinaryOperator *B,40                                     CheckerContext &C) const {41  // When doing pointer subtraction, if the two pointers do not point to the42  // same array, emit a warning.43  if (B->getOpcode() != BO_Sub)44    return;45 46  SVal LV = C.getSVal(B->getLHS());47  SVal RV = C.getSVal(B->getRHS());48 49  const MemRegion *LR = LV.getAsRegion();50  const MemRegion *RR = RV.getAsRegion();51  if (!LR || !RR)52    return;53 54  // Allow subtraction of identical pointers.55  if (LR == RR)56    return;57 58  // No warning if one operand is unknown or resides in a region that could be59  // equal to the other.60  if (LR->getSymbolicBase() || RR->getSymbolicBase())61    return;62 63  if (!B->getLHS()->getType()->isPointerType() ||64      !B->getRHS()->getType()->isPointerType())65    return;66 67  const auto *ElemLR = dyn_cast<ElementRegion>(LR);68  const auto *ElemRR = dyn_cast<ElementRegion>(RR);69 70  // Allow cases like "(&x + 1) - &x".71  if (ElemLR && ElemLR->getSuperRegion() == RR)72    return;73  // Allow cases like "&x - (&x + 1)".74  if (ElemRR && ElemRR->getSuperRegion() == LR)75    return;76 77  const ValueDecl *DiffDeclL = nullptr;78  const ValueDecl *DiffDeclR = nullptr;79 80  if (ElemLR && ElemRR) {81    const MemRegion *SuperLR = ElemLR->getSuperRegion();82    const MemRegion *SuperRR = ElemRR->getSuperRegion();83    if (SuperLR == SuperRR)84      return;85    // Allow arithmetic on different symbolic regions.86    if (isa<SymbolicRegion>(SuperLR) || isa<SymbolicRegion>(SuperRR))87      return;88    if (const auto *SuperDLR = dyn_cast<DeclRegion>(SuperLR))89      DiffDeclL = SuperDLR->getDecl();90    if (const auto *SuperDRR = dyn_cast<DeclRegion>(SuperRR))91      DiffDeclR = SuperDRR->getDecl();92  }93 94  if (ExplodedNode *N = C.generateNonFatalErrorNode()) {95    auto R =96        std::make_unique<PathSensitiveBugReport>(BT, Msg_MemRegionDifferent, N);97    R->addRange(B->getSourceRange());98    // The declarations may be identical even if the regions are different:99    //   struct { int array[10]; } a, b;100    //   do_something(&a.array[5] - &b.array[5]);101    // In this case don't emit notes.102    if (DiffDeclL != DiffDeclR) {103      auto AddNote = [&R, &C](const ValueDecl *D, StringRef SideStr) {104        if (D) {105          std::string Msg = llvm::formatv(106              "{0} at the {1}-hand side of subtraction",107              D->getType()->isArrayType() ? "Array" : "Object", SideStr);108          R->addNote(Msg, {D, C.getSourceManager()});109        }110      };111      AddNote(DiffDeclL, "left");112      AddNote(DiffDeclR, "right");113    }114    C.emitReport(std::move(R));115  }116}117 118void ento::registerPointerSubChecker(CheckerManager &mgr) {119  mgr.registerChecker<PointerSubChecker>();120}121 122bool ento::shouldRegisterPointerSubChecker(const CheckerManager &mgr) {123  return true;124}125