PointerSubChecker.cpp revision 355940
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 21using namespace clang; 22using namespace ento; 23 24namespace { 25class PointerSubChecker 26 : public Checker< check::PreStmt<BinaryOperator> > { 27 mutable std::unique_ptr<BuiltinBug> BT; 28 29public: 30 void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const; 31}; 32} 33 34void 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 72void ento::registerPointerSubChecker(CheckerManager &mgr) { 73 mgr.registerChecker<PointerSubChecker>(); 74} 75 76bool ento::shouldRegisterPointerSubChecker(const LangOptions &LO) { 77 return true; 78} 79