1//=== PointerArithChecker.cpp - Pointer arithmetic checker -----*- C++ -*--===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This files defines PointerArithChecker, a builtin checker that checks for 11// pointer arithmetic on locations other than array elements. 12// 13//===----------------------------------------------------------------------===// 14 15#include "ClangSACheckers.h" 16#include "clang/StaticAnalyzer/Core/Checker.h" 17#include "clang/StaticAnalyzer/Core/CheckerManager.h" 18#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 19#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 20 21using namespace clang; 22using namespace ento; 23 24namespace { 25class PointerArithChecker 26 : public Checker< check::PreStmt<BinaryOperator> > { 27 mutable OwningPtr<BuiltinBug> BT; 28 29public: 30 void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const; 31}; 32} 33 34void PointerArithChecker::checkPreStmt(const BinaryOperator *B, 35 CheckerContext &C) const { 36 if (B->getOpcode() != BO_Sub && B->getOpcode() != BO_Add) 37 return; 38 39 ProgramStateRef state = C.getState(); 40 const LocationContext *LCtx = C.getLocationContext(); 41 SVal LV = state->getSVal(B->getLHS(), LCtx); 42 SVal RV = state->getSVal(B->getRHS(), LCtx); 43 44 const MemRegion *LR = LV.getAsRegion(); 45 46 if (!LR || !RV.isConstant()) 47 return; 48 49 // If pointer arithmetic is done on variables of non-array type, this often 50 // means behavior rely on memory organization, which is dangerous. 51 if (isa<VarRegion>(LR) || isa<CodeTextRegion>(LR) || 52 isa<CompoundLiteralRegion>(LR)) { 53 54 if (ExplodedNode *N = C.addTransition()) { 55 if (!BT) 56 BT.reset(new BuiltinBug("Dangerous pointer arithmetic", 57 "Pointer arithmetic done on non-array variables " 58 "means reliance on memory layout, which is " 59 "dangerous.")); 60 BugReport *R = new BugReport(*BT, BT->getDescription(), N); 61 R->addRange(B->getSourceRange()); 62 C.EmitReport(R); 63 } 64 } 65} 66 67void ento::registerPointerArithChecker(CheckerManager &mgr) { 68 mgr.registerChecker<PointerArithChecker>(); 69} 70