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 "ExprEngineInternalChecks.h" 16 #include "clang/StaticAnalyzer/BugReporter/BugType.h" 17 #include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h" 18 19 using namespace clang; 20 using namespace ento; 21 22 namespace { 23 class PointerArithChecker 24 : public CheckerVisitor<PointerArithChecker> { 25 BuiltinBug *BT; 26 public: 27 PointerArithChecker() : BT(0) {} 28 static void *getTag(); 29 void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B); 30 }; 31 } 32 33 void *PointerArithChecker::getTag() { 34 static int x; 35 return &x; 36 } 37 38 void PointerArithChecker::PreVisitBinaryOperator(CheckerContext &C, 39 const BinaryOperator *B) { 40 if (B->getOpcode() != BO_Sub && B->getOpcode() != BO_Add) 41 return; 42 43 const GRState *state = C.getState(); 44 SVal LV = state->getSVal(B->getLHS()); 45 SVal RV = state->getSVal(B->getRHS()); 46 47 const MemRegion *LR = LV.getAsRegion(); 48 49 if (!LR || !RV.isConstant()) 50 return; 51 52 // If pointer arithmetic is done on variables of non-array type, this often 53 // means behavior rely on memory organization, which is dangerous. 54 if (isa<VarRegion>(LR) || isa<CodeTextRegion>(LR) || 55 isa<CompoundLiteralRegion>(LR)) { 56 57 if (ExplodedNode *N = C.generateNode()) { 58 if (!BT) 59 BT = new BuiltinBug("Dangerous pointer arithmetic", 60 "Pointer arithmetic done on non-array variables " 61 "means reliance on memory layout, which is " 62 "dangerous."); 63 RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N); 64 R->addRange(B->getSourceRange()); 65 C.EmitReport(R); 66 } 67 } 68 } 69 70 void ento::RegisterPointerArithChecker(ExprEngine &Eng) { 71 Eng.registerCheck(new PointerArithChecker()); 72 } 73