Coverage Report

Created: 2017-10-03 07:32

/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
Line
Count
Source (jump to first uncovered line)
1
//=== VLASizeChecker.cpp - Undefined dereference 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 defines VLASizeChecker, a builtin check in ExprEngine that
11
// performs checks for declaration of VLA of undefined or zero size.
12
// In addition, VLASizeChecker is responsible for defining the extent
13
// of the MemRegion that represents a VLA.
14
//
15
//===----------------------------------------------------------------------===//
16
17
#include "ClangSACheckers.h"
18
#include "clang/AST/CharUnits.h"
19
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
20
#include "clang/StaticAnalyzer/Core/Checker.h"
21
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
22
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
23
#include "llvm/ADT/STLExtras.h"
24
#include "llvm/ADT/SmallString.h"
25
#include "llvm/Support/raw_ostream.h"
26
27
using namespace clang;
28
using namespace ento;
29
30
namespace {
31
class VLASizeChecker : public Checker< check::PreStmt<DeclStmt> > {
32
  mutable std::unique_ptr<BugType> BT;
33
  enum VLASize_Kind { VLA_Garbage, VLA_Zero, VLA_Tainted, VLA_Negative };
34
35
  void reportBug(VLASize_Kind Kind,
36
                 const Expr *SizeE,
37
                 ProgramStateRef State,
38
                 CheckerContext &C) const;
39
public:
40
  void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const;
41
};
42
} // end anonymous namespace
43
44
void VLASizeChecker::reportBug(VLASize_Kind Kind,
45
                               const Expr *SizeE,
46
                               ProgramStateRef State,
47
8
                               CheckerContext &C) const {
48
8
  // Generate an error node.
49
8
  ExplodedNode *N = C.generateErrorNode(State);
50
8
  if (!N)
51
0
    return;
52
8
53
8
  
if (8
!BT8
)
54
2
    BT.reset(new BuiltinBug(
55
2
        this, "Dangerous variable-length array (VLA) declaration"));
56
8
57
8
  SmallString<256> buf;
58
8
  llvm::raw_svector_ostream os(buf);
59
8
  os << "Declared variable-length array (VLA) ";
60
8
  switch (Kind) {
61
1
  case VLA_Garbage:
62
1
    os << "uses a garbage value as its size";
63
1
    break;
64
1
  case VLA_Zero:
65
1
    os << "has zero size";
66
1
    break;
67
1
  case VLA_Tainted:
68
1
    os << "has tainted size";
69
1
    break;
70
5
  case VLA_Negative:
71
5
    os << "has negative size";
72
5
    break;
73
8
  }
74
8
75
8
  auto report = llvm::make_unique<BugReport>(*BT, os.str(), N);
76
8
  report->addRange(SizeE->getSourceRange());
77
8
  bugreporter::trackNullOrUndefValue(N, SizeE, *report);
78
8
  C.emitReport(std::move(report));
79
8
}
80
81
8.26k
void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
82
8.26k
  if (!DS->isSingleDecl())
83
0
    return;
84
8.26k
85
8.26k
  const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
86
8.26k
  if (!VD)
87
0
    return;
88
8.26k
89
8.26k
  ASTContext &Ctx = C.getASTContext();
90
8.26k
  const VariableArrayType *VLA = Ctx.getAsVariableArrayType(VD->getType());
91
8.26k
  if (!VLA)
92
8.23k
    return;
93
37
94
37
  // FIXME: Handle multi-dimensional VLAs.
95
37
  const Expr *SE = VLA->getSizeExpr();
96
37
  ProgramStateRef state = C.getState();
97
37
  SVal sizeV = state->getSVal(SE, C.getLocationContext());
98
37
99
37
  if (
sizeV.isUndef()37
) {
100
1
    reportBug(VLA_Garbage, SE, state, C);
101
1
    return;
102
1
  }
103
36
104
36
  // See if the size value is known. It can't be undefined because we would have
105
36
  // warned about that already.
106
36
  
if (36
sizeV.isUnknown()36
)
107
3
    return;
108
33
109
33
  // Check if the size is tainted.
110
33
  
if (33
state->isTainted(sizeV)33
) {
111
1
    reportBug(VLA_Tainted, SE, nullptr, C);
112
1
    return;
113
1
  }
114
32
115
32
  // Check if the size is zero.
116
32
  DefinedSVal sizeD = sizeV.castAs<DefinedSVal>();
117
32
118
32
  ProgramStateRef stateNotZero, stateZero;
119
32
  std::tie(stateNotZero, stateZero) = state->assume(sizeD);
120
32
121
32
  if (
stateZero && 32
!stateNotZero7
) {
122
1
    reportBug(VLA_Zero, SE, stateZero, C);
123
1
    return;
124
1
  }
125
31
126
31
  // From this point on, assume that the size is not zero.
127
31
  state = stateNotZero;
128
31
129
31
  // VLASizeChecker is responsible for defining the extent of the array being
130
31
  // declared. We do this by multiplying the array length by the element size,
131
31
  // then matching that with the array region's extent symbol.
132
31
133
31
  // Check if the size is negative.
134
31
  SValBuilder &svalBuilder = C.getSValBuilder();
135
31
136
31
  QualType Ty = SE->getType();
137
31
  DefinedOrUnknownSVal Zero = svalBuilder.makeZeroVal(Ty);
138
31
139
31
  SVal LessThanZeroVal = svalBuilder.evalBinOp(state, BO_LT, sizeD, Zero, Ty);
140
31
  if (Optional<DefinedSVal> LessThanZeroDVal =
141
31
        LessThanZeroVal.getAs<DefinedSVal>()) {
142
31
    ConstraintManager &CM = C.getConstraintManager();
143
31
    ProgramStateRef StatePos, StateNeg;
144
31
145
31
    std::tie(StateNeg, StatePos) = CM.assumeDual(state, *LessThanZeroDVal);
146
31
    if (
StateNeg && 31
!StatePos13
) {
147
5
      reportBug(VLA_Negative, SE, state, C);
148
5
      return;
149
5
    }
150
26
    state = StatePos;
151
26
  }
152
31
153
31
  // Convert the array length to size_t.
154
26
  QualType SizeTy = Ctx.getSizeType();
155
26
  NonLoc ArrayLength =
156
26
      svalBuilder.evalCast(sizeD, SizeTy, SE->getType()).castAs<NonLoc>();
157
26
158
26
  // Get the element size.
159
26
  CharUnits EleSize = Ctx.getTypeSizeInChars(VLA->getElementType());
160
26
  SVal EleSizeVal = svalBuilder.makeIntVal(EleSize.getQuantity(), SizeTy);
161
26
162
26
  // Multiply the array length by the element size.
163
26
  SVal ArraySizeVal = svalBuilder.evalBinOpNN(
164
26
      state, BO_Mul, ArrayLength, EleSizeVal.castAs<NonLoc>(), SizeTy);
165
26
166
26
  // Finally, assume that the array's extent matches the given size.
167
26
  const LocationContext *LC = C.getLocationContext();
168
26
  DefinedOrUnknownSVal Extent =
169
26
    state->getRegion(VD, LC)->getExtent(svalBuilder);
170
26
  DefinedOrUnknownSVal ArraySize = ArraySizeVal.castAs<DefinedOrUnknownSVal>();
171
26
  DefinedOrUnknownSVal sizeIsKnown =
172
26
    svalBuilder.evalEQ(state, Extent, ArraySize);
173
26
  state = state->assume(sizeIsKnown, true);
174
26
175
26
  // Assume should not fail at this point.
176
26
  assert(state);
177
26
178
26
  // Remember our assumptions!
179
26
  C.addTransition(state);
180
26
}
181
182
417
void ento::registerVLASizeChecker(CheckerManager &mgr) {
183
417
  mgr.registerChecker<VLASizeChecker>();
184
417
}