aboutsummaryrefslogtreecommitdiff
path: root/lib/Analysis/VLASizeChecker.cpp
blob: 49e19434cb7ef4fb19b76331c2d329428a69cf2b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//=== VLASizeChecker.cpp - Undefined dereference checker --------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This defines two VLASizeCheckers, a builtin check in GRExprEngine that 
// performs checks for declaration of VLA of undefined or zero size.
//
//===----------------------------------------------------------------------===//

#include "GRExprEngineInternalChecks.h"
#include "clang/Analysis/PathSensitive/Checker.h"
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"

using namespace clang;

namespace {
class VISIBILITY_HIDDEN UndefSizedVLAChecker : public Checker {
  BugType *BT;
  
public:
  UndefSizedVLAChecker() : BT(0) {}
  static void *getTag();
  ExplodedNode *CheckType(QualType T, ExplodedNode *Pred, 
                          const GRState *state, Stmt *S, GRExprEngine &Eng);
};

class VISIBILITY_HIDDEN ZeroSizedVLAChecker : public Checker {
  BugType *BT;
  
public:
  ZeroSizedVLAChecker() : BT(0) {}
  static void *getTag();
  ExplodedNode *CheckType(QualType T, ExplodedNode *Pred, 
                          const GRState *state, Stmt *S, GRExprEngine &Eng);
};
} // end anonymous namespace

void clang::RegisterVLASizeChecker(GRExprEngine &Eng) {
  Eng.registerCheck(new UndefSizedVLAChecker());
  Eng.registerCheck(new ZeroSizedVLAChecker());
}

void *UndefSizedVLAChecker::getTag() {
  static int x = 0;
  return &x;
}

ExplodedNode *UndefSizedVLAChecker::CheckType(QualType T, ExplodedNode *Pred,
                                              const GRState *state,
                                              Stmt *S, GRExprEngine &Eng) {
  GRStmtNodeBuilder &Builder = Eng.getBuilder();
  BugReporter &BR = Eng.getBugReporter();

  if (VariableArrayType* VLA = dyn_cast<VariableArrayType>(T)) {
    // FIXME: Handle multi-dimensional VLAs.
    Expr* SE = VLA->getSizeExpr();
    SVal Size_untested = state->getSVal(SE);

    if (Size_untested.isUndef()) {
      if (ExplodedNode* N = Builder.generateNode(S, state, Pred)) {
        N->markAsSink();
        if (!BT)
          BT = new BuiltinBug("Declared variable-length array (VLA) uses a "
                              "garbage value as its size");

        EnhancedBugReport *R =
                          new EnhancedBugReport(*BT, BT->getName().c_str(), N);
        R->addRange(SE->getSourceRange());
        R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
        BR.EmitReport(R);
      }
      return 0;    
    }
  }
  return Pred;
}

void *ZeroSizedVLAChecker::getTag() {
  static int x;
  return &x;
}

ExplodedNode *ZeroSizedVLAChecker::CheckType(QualType T, ExplodedNode *Pred, 
                                             const GRState *state, Stmt *S, 
                                             GRExprEngine &Eng) {
  GRStmtNodeBuilder &Builder = Eng.getBuilder();
  BugReporter &BR = Eng.getBugReporter();

  if (VariableArrayType* VLA = dyn_cast<VariableArrayType>(T)) {
    // FIXME: Handle multi-dimensional VLAs.
    Expr* SE = VLA->getSizeExpr();
    SVal Size_untested = state->getSVal(SE);

    DefinedOrUnknownSVal *Size = dyn_cast<DefinedOrUnknownSVal>(&Size_untested);
    // Undefined size is checked in another checker.
    if (!Size)
      return Pred;

    const GRState *zeroState =  state->Assume(*Size, false);
    state = state->Assume(*Size, true);

    if (zeroState && !state) {
      if (ExplodedNode* N = Builder.generateNode(S, zeroState, Pred)) {
        N->markAsSink();
        if (!BT)
          BT = new BugType("Declared variable-length array (VLA) has zero size",
                            "Logic error");

        EnhancedBugReport *R =
                          new EnhancedBugReport(*BT, BT->getName().c_str(), N);
        R->addRange(SE->getSourceRange());
        R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
        BR.EmitReport(R);
      }
    }
    if (!state)
      return 0;

    return Builder.generateNode(S, state, Pred);
  }
  else
    return Pred;
}