xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp (revision d99bd55a5e092774214ba31fc5a871bfc31e711c)
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