Home | History | Annotate | Download | only in Checkers
      1 //=== PointerSubChecker.cpp - Pointer subtraction 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 PointerSubChecker, a builtin checker that checks for
     11 // pointer subtractions on two pointers pointing to different memory chunks.
     12 // This check corresponds to CWE-469.
     13 //
     14 //===----------------------------------------------------------------------===//
     15 
     16 #include "ClangSACheckers.h"
     17 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
     18 #include "clang/StaticAnalyzer/Core/Checker.h"
     19 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
     20 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
     21 
     22 using namespace clang;
     23 using namespace ento;
     24 
     25 namespace {
     26 class PointerSubChecker
     27   : public Checker< check::PreStmt<BinaryOperator> > {
     28   mutable std::unique_ptr<BuiltinBug> BT;
     29 
     30 public:
     31   void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
     32 };
     33 }
     34 
     35 void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
     36                                      CheckerContext &C) const {
     37   // When doing pointer subtraction, if the two pointers do not point to the
     38   // same memory chunk, emit a warning.
     39   if (B->getOpcode() != BO_Sub)
     40     return;
     41 
     42   ProgramStateRef state = C.getState();
     43   const LocationContext *LCtx = C.getLocationContext();
     44   SVal LV = state->getSVal(B->getLHS(), LCtx);
     45   SVal RV = state->getSVal(B->getRHS(), LCtx);
     46 
     47   const MemRegion *LR = LV.getAsRegion();
     48   const MemRegion *RR = RV.getAsRegion();
     49 
     50   if (!(LR && RR))
     51     return;
     52 
     53   const MemRegion *BaseLR = LR->getBaseRegion();
     54   const MemRegion *BaseRR = RR->getBaseRegion();
     55 
     56   if (BaseLR == BaseRR)
     57     return;
     58 
     59   // Allow arithmetic on different symbolic regions.
     60   if (isa<SymbolicRegion>(BaseLR) || isa<SymbolicRegion>(BaseRR))
     61     return;
     62 
     63   if (ExplodedNode *N = C.addTransition()) {
     64     if (!BT)
     65       BT.reset(
     66           new BuiltinBug(this, "Pointer subtraction",
     67                          "Subtraction of two pointers that do not point to "
     68                          "the same memory chunk may cause incorrect result."));
     69     BugReport *R = new BugReport(*BT, BT->getDescription(), N);
     70     R->addRange(B->getSourceRange());
     71     C.emitReport(R);
     72   }
     73 }
     74 
     75 void ento::registerPointerSubChecker(CheckerManager &mgr) {
     76   mgr.registerChecker<PointerSubChecker>();
     77 }
     78