Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- DereferenceChecker.cpp - Null dereference checker -----------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This defines NullDerefChecker, a builtin check in ExprEngine that performs
10
// checks for null pointers at loads and stores.
11
//
12
//===----------------------------------------------------------------------===//
13
14
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
15
#include "clang/AST/ExprObjC.h"
16
#include "clang/AST/ExprOpenMP.h"
17
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
18
#include "clang/StaticAnalyzer/Core/Checker.h"
19
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
20
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
21
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
22
#include "llvm/ADT/SmallString.h"
23
#include "llvm/Support/raw_ostream.h"
24
25
using namespace clang;
26
using namespace ento;
27
28
namespace {
29
class DereferenceChecker
30
    : public Checker< check::Location,
31
                      check::Bind,
32
                      EventDispatcher<ImplicitNullDerefEvent> > {
33
  mutable std::unique_ptr<BuiltinBug> BT_null;
34
  mutable std::unique_ptr<BuiltinBug> BT_undef;
35
36
  void reportBug(ProgramStateRef State, const Stmt *S, CheckerContext &C) const;
37
38
public:
39
  void checkLocation(SVal location, bool isLoad, const Stmt* S,
40
                     CheckerContext &C) const;
41
  void checkBind(SVal L, SVal V, const Stmt *S, CheckerContext &C) const;
42
43
  static void AddDerefSource(raw_ostream &os,
44
                             SmallVectorImpl<SourceRange> &Ranges,
45
                             const Expr *Ex, const ProgramState *state,
46
                             const LocationContext *LCtx,
47
                             bool loadedFrom = false);
48
};
49
} // end anonymous namespace
50
51
void
52
DereferenceChecker::AddDerefSource(raw_ostream &os,
53
                                   SmallVectorImpl<SourceRange> &Ranges,
54
                                   const Expr *Ex,
55
                                   const ProgramState *state,
56
                                   const LocationContext *LCtx,
57
721
                                   bool loadedFrom) {
58
721
  Ex = Ex->IgnoreParenLValueCasts();
59
721
  switch (Ex->getStmtClass()) {
60
721
    default:
61
104
      break;
62
721
    case Stmt::DeclRefExprClass: {
63
588
      const DeclRefExpr *DR = cast<DeclRefExpr>(Ex);
64
588
      if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
65
588
        os << " (" << (loadedFrom ? 
"loaded from"580
:
"from"8
)
66
588
           << " variable '" <<  VD->getName() << "')";
67
588
        Ranges.push_back(DR->getSourceRange());
68
588
      }
69
588
      break;
70
721
    }
71
721
    case Stmt::MemberExprClass: {
72
24
      const MemberExpr *ME = cast<MemberExpr>(Ex);
73
24
      os << " (" << (loadedFrom ? 
"loaded from"19
:
"via"5
)
74
24
         << " field '" << ME->getMemberNameInfo() << "')";
75
24
      SourceLocation L = ME->getMemberLoc();
76
24
      Ranges.push_back(SourceRange(L, L));
77
24
      break;
78
721
    }
79
721
    case Stmt::ObjCIvarRefExprClass: {
80
5
      const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(Ex);
81
5
      os << " (" << (loadedFrom ? 
"loaded from"3
:
"via"2
)
82
5
         << " ivar '" << IV->getDecl()->getName() << "')";
83
5
      SourceLocation L = IV->getLocation();
84
5
      Ranges.push_back(SourceRange(L, L));
85
5
      break;
86
721
    }
87
721
  }
88
721
}
89
90
740
static const Expr *getDereferenceExpr(const Stmt *S, bool IsBind=false){
91
740
  const Expr *E = nullptr;
92
740
93
740
  // Walk through lvalue casts to get the original expression
94
740
  // that syntactically caused the load.
95
740
  if (const Expr *expr = dyn_cast<Expr>(S))
96
736
    E = expr->IgnoreParenLValueCasts();
97
740
98
740
  if (IsBind) {
99
8
    const VarDecl *VD;
100
8
    const Expr *Init;
101
8
    std::tie(VD, Init) = parseAssignment(S);
102
8
    if (VD && 
Init4
)
103
4
      E = Init;
104
8
  }
105
740
  return E;
106
740
}
107
108
740
static bool suppressReport(const Expr *E) {
109
740
  // Do not report dereferences on memory in non-default address spaces.
110
740
  return E->getType().getQualifiers().hasAddressSpace();
111
740
}
112
113
8
static bool isDeclRefExprToReference(const Expr *E) {
114
8
  if (const auto *DRE = dyn_cast<DeclRefExpr>(E))
115
1
    return DRE->getDecl()->getType()->isReferenceType();
116
7
  return false;
117
7
}
118
119
void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S,
120
730
                                   CheckerContext &C) const {
121
730
  // Generate an error node.
122
730
  ExplodedNode *N = C.generateErrorNode(State);
123
730
  if (!N)
124
0
    return;
125
730
126
730
  // We know that 'location' cannot be non-null.  This is what
127
730
  // we call an "explicit" null dereference.
128
730
  if (!BT_null)
129
146
    BT_null.reset(new BuiltinBug(this, "Dereference of null pointer"));
130
730
131
730
  SmallString<100> buf;
132
730
  llvm::raw_svector_ostream os(buf);
133
730
134
730
  SmallVector<SourceRange, 2> Ranges;
135
730
136
730
  switch (S->getStmtClass()) {
137
730
  case Stmt::ArraySubscriptExprClass: {
138
16
    os << "Array access";
139
16
    const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S);
140
16
    AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(),
141
16
                   State.get(), N->getLocationContext());
142
16
    os << " results in a null pointer dereference";
143
16
    break;
144
730
  }
145
730
  case Stmt::OMPArraySectionExprClass: {
146
0
    os << "Array access";
147
0
    const OMPArraySectionExpr *AE = cast<OMPArraySectionExpr>(S);
148
0
    AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(),
149
0
                   State.get(), N->getLocationContext());
150
0
    os << " results in a null pointer dereference";
151
0
    break;
152
730
  }
153
730
  case Stmt::UnaryOperatorClass: {
154
679
    os << "Dereference of null pointer";
155
679
    const UnaryOperator *U = cast<UnaryOperator>(S);
156
679
    AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(),
157
679
                   State.get(), N->getLocationContext(), true);
158
679
    break;
159
730
  }
160
730
  case Stmt::MemberExprClass: {
161
20
    const MemberExpr *M = cast<MemberExpr>(S);
162
20
    if (M->isArrow() || 
isDeclRefExprToReference(M->getBase())8
) {
163
13
      os << "Access to field '" << M->getMemberNameInfo()
164
13
         << "' results in a dereference of a null pointer";
165
13
      AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(),
166
13
                     State.get(), N->getLocationContext(), true);
167
13
    }
168
20
    break;
169
730
  }
170
730
  case Stmt::ObjCIvarRefExprClass: {
171
13
    const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(S);
172
13
    os << "Access to instance variable '" << *IV->getDecl()
173
13
       << "' results in a dereference of a null pointer";
174
13
    AddDerefSource(os, Ranges, IV->getBase()->IgnoreParenCasts(),
175
13
                   State.get(), N->getLocationContext(), true);
176
13
    break;
177
730
  }
178
730
  default:
179
2
    break;
180
730
  }
181
730
182
730
  auto report = llvm::make_unique<BugReport>(
183
730
      *BT_null, buf.empty() ? 
BT_null->getDescription()9
:
StringRef(buf)721
, N);
184
730
185
730
  bugreporter::trackExpressionValue(N, bugreporter::getDerefExpr(S), *report);
186
730
187
730
  for (SmallVectorImpl<SourceRange>::iterator
188
1.34k
       I = Ranges.begin(), E = Ranges.end(); I!=E; 
++I617
)
189
617
    report->addRange(*I);
190
730
191
730
  C.emitReport(std::move(report));
192
730
}
193
194
void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
195
175k
                                       CheckerContext &C) const {
196
175k
  // Check for dereference of an undefined value.
197
175k
  if (l.isUndef()) {
198
8
    if (ExplodedNode *N = C.generateErrorNode()) {
199
8
      if (!BT_undef)
200
6
        BT_undef.reset(
201
6
            new BuiltinBug(this, "Dereference of undefined pointer value"));
202
8
203
8
      auto report =
204
8
          llvm::make_unique<BugReport>(*BT_undef, BT_undef->getDescription(), N);
205
8
      bugreporter::trackExpressionValue(N, bugreporter::getDerefExpr(S), *report);
206
8
      C.emitReport(std::move(report));
207
8
    }
208
8
    return;
209
8
  }
210
175k
211
175k
  DefinedOrUnknownSVal location = l.castAs<DefinedOrUnknownSVal>();
212
175k
213
175k
  // Check for null dereferences.
214
175k
  if (!location.getAs<Loc>())
215
0
    return;
216
175k
217
175k
  ProgramStateRef state = C.getState();
218
175k
219
175k
  ProgramStateRef notNullState, nullState;
220
175k
  std::tie(notNullState, nullState) = state->assume(location);
221
175k
222
175k
  // The explicit NULL case.
223
175k
  if (nullState) {
224
3.74k
    if (!notNullState) {
225
732
      const Expr *expr = getDereferenceExpr(S);
226
732
      if (!suppressReport(expr)) {
227
723
        reportBug(nullState, expr, C);
228
723
        return;
229
723
      }
230
3.02k
    }
231
3.02k
232
3.02k
    // Otherwise, we have the case where the location could either be
233
3.02k
    // null or not-null.  Record the error node as an "implicit" null
234
3.02k
    // dereference.
235
3.02k
    if (ExplodedNode *N = C.generateSink(nullState, C.getPredecessor())) {
236
3.01k
      ImplicitNullDerefEvent event = {l, isLoad, N, &C.getBugReporter(),
237
3.01k
                                      /*IsDirectDereference=*/true};
238
3.01k
      dispatchEvent(event);
239
3.01k
    }
240
3.02k
  }
241
175k
242
175k
  // From this point forward, we know that the location is not null.
243
175k
  C.addTransition(notNullState);
244
174k
}
245
246
void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S,
247
65.5k
                                   CheckerContext &C) const {
248
65.5k
  // If we're binding to a reference, check if the value is known to be null.
249
65.5k
  if (V.isUndef())
250
56
    return;
251
65.4k
252
65.4k
  const MemRegion *MR = L.getAsRegion();
253
65.4k
  const TypedValueRegion *TVR = dyn_cast_or_null<TypedValueRegion>(MR);
254
65.4k
  if (!TVR)
255
518
    return;
256
64.9k
257
64.9k
  if (!TVR->getValueType()->isReferenceType())
258
64.3k
    return;
259
573
260
573
  ProgramStateRef State = C.getState();
261
573
262
573
  ProgramStateRef StNonNull, StNull;
263
573
  std::tie(StNonNull, StNull) = State->assume(V.castAs<DefinedOrUnknownSVal>());
264
573
265
573
  if (StNull) {
266
23
    if (!StNonNull) {
267
8
      const Expr *expr = getDereferenceExpr(S, /*IsBind=*/true);
268
8
      if (!suppressReport(expr)) {
269
7
        reportBug(StNull, expr, C);
270
7
        return;
271
7
      }
272
16
    }
273
16
274
16
    // At this point the value could be either null or non-null.
275
16
    // Record this as an "implicit" null dereference.
276
16
    if (ExplodedNode *N = C.generateSink(StNull, C.getPredecessor())) {
277
16
      ImplicitNullDerefEvent event = {V, /*isLoad=*/true, N,
278
16
                                      &C.getBugReporter(),
279
16
                                      /*IsDirectDereference=*/true};
280
16
      dispatchEvent(event);
281
16
    }
282
16
  }
283
573
284
573
  // Unlike a regular null dereference, initializing a reference with a
285
573
  // dereferenced null pointer does not actually cause a runtime exception in
286
573
  // Clang's implementation of references.
287
573
  //
288
573
  //   int &r = *p; // safe??
289
573
  //   if (p != NULL) return; // uh-oh
290
573
  //   r = 5; // trap here
291
573
  //
292
573
  // The standard says this is invalid as soon as we try to create a "null
293
573
  // reference" (there is no such thing), but turning this into an assumption
294
573
  // that 'p' is never null will not match our actual runtime behavior.
295
573
  // So we do not record this assumption, allowing us to warn on the last line
296
573
  // of this example.
297
573
  //
298
573
  // We do need to add a transition because we may have generated a sink for
299
573
  // the "implicit" null dereference.
300
573
  C.addTransition(State, this);
301
566
}
302
303
683
void ento::registerDereferenceChecker(CheckerManager &mgr) {
304
683
  mgr.registerChecker<DereferenceChecker>();
305
683
}
306
307
684
bool ento::shouldRegisterDereferenceChecker(const LangOptions &LO) {
308
684
  return true;
309
684
}