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