xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp (revision f99d595cfd32465c97fe1dea2638d7f967ef6089)
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 "InternalChecks.h"
17 #include "clang/StaticAnalyzer/BugReporter/BugType.h"
18 #include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
19 
20 using namespace clang;
21 using namespace ento;
22 
23 namespace {
24 class PointerSubChecker
25   : public CheckerVisitor<PointerSubChecker> {
26   BuiltinBug *BT;
27 public:
28   PointerSubChecker() : BT(0) {}
29   static void *getTag();
30   void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
31 };
32 }
33 
34 void *PointerSubChecker::getTag() {
35   static int x;
36   return &x;
37 }
38 
39 void PointerSubChecker::PreVisitBinaryOperator(CheckerContext &C,
40                                                const BinaryOperator *B) {
41   // When doing pointer subtraction, if the two pointers do not point to the
42   // same memory chunk, emit a warning.
43   if (B->getOpcode() != BO_Sub)
44     return;
45 
46   const GRState *state = C.getState();
47   SVal LV = state->getSVal(B->getLHS());
48   SVal RV = state->getSVal(B->getRHS());
49 
50   const MemRegion *LR = LV.getAsRegion();
51   const MemRegion *RR = RV.getAsRegion();
52 
53   if (!(LR && RR))
54     return;
55 
56   const MemRegion *BaseLR = LR->getBaseRegion();
57   const MemRegion *BaseRR = RR->getBaseRegion();
58 
59   if (BaseLR == BaseRR)
60     return;
61 
62   // Allow arithmetic on different symbolic regions.
63   if (isa<SymbolicRegion>(BaseLR) || isa<SymbolicRegion>(BaseRR))
64     return;
65 
66   if (ExplodedNode *N = C.generateNode()) {
67     if (!BT)
68       BT = new BuiltinBug("Pointer subtraction",
69                           "Subtraction of two pointers that do not point to "
70                           "the same memory chunk may cause incorrect result.");
71     RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N);
72     R->addRange(B->getSourceRange());
73     C.EmitReport(R);
74   }
75 }
76 
77 void ento::RegisterPointerSubChecker(ExprEngine &Eng) {
78   Eng.registerCheck(new PointerSubChecker());
79 }
80