clang  8.0.0svn
DereferenceChecker.cpp
Go to the documentation of this file.
1 //== NullDerefChecker.cpp - Null 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 NullDerefChecker, a builtin check in ExprEngine that performs
11 // checks for null pointers at loads and stores.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "ClangSACheckers.h"
16 #include "clang/AST/ExprObjC.h"
17 #include "clang/AST/ExprOpenMP.h"
23 #include "llvm/ADT/SmallString.h"
24 #include "llvm/Support/raw_ostream.h"
25 
26 using namespace clang;
27 using namespace ento;
28 
29 namespace {
30 class DereferenceChecker
31  : public Checker< check::Location,
32  check::Bind,
33  EventDispatcher<ImplicitNullDerefEvent> > {
34  mutable std::unique_ptr<BuiltinBug> BT_null;
35  mutable std::unique_ptr<BuiltinBug> BT_undef;
36 
37  void reportBug(ProgramStateRef State, const Stmt *S, CheckerContext &C) const;
38 
39 public:
40  void checkLocation(SVal location, bool isLoad, const Stmt* S,
41  CheckerContext &C) const;
42  void checkBind(SVal L, SVal V, const Stmt *S, CheckerContext &C) const;
43 
44  static void AddDerefSource(raw_ostream &os,
46  const Expr *Ex, const ProgramState *state,
47  const LocationContext *LCtx,
48  bool loadedFrom = false);
49 };
50 } // end anonymous namespace
51 
52 void
53 DereferenceChecker::AddDerefSource(raw_ostream &os,
55  const Expr *Ex,
56  const ProgramState *state,
57  const LocationContext *LCtx,
58  bool loadedFrom) {
59  Ex = Ex->IgnoreParenLValueCasts();
60  switch (Ex->getStmtClass()) {
61  default:
62  break;
63  case Stmt::DeclRefExprClass: {
64  const DeclRefExpr *DR = cast<DeclRefExpr>(Ex);
65  if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
66  os << " (" << (loadedFrom ? "loaded from" : "from")
67  << " variable '" << VD->getName() << "')";
68  Ranges.push_back(DR->getSourceRange());
69  }
70  break;
71  }
72  case Stmt::MemberExprClass: {
73  const MemberExpr *ME = cast<MemberExpr>(Ex);
74  os << " (" << (loadedFrom ? "loaded from" : "via")
75  << " field '" << ME->getMemberNameInfo() << "')";
76  SourceLocation L = ME->getMemberLoc();
77  Ranges.push_back(SourceRange(L, L));
78  break;
79  }
80  case Stmt::ObjCIvarRefExprClass: {
81  const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(Ex);
82  os << " (" << (loadedFrom ? "loaded from" : "via")
83  << " ivar '" << IV->getDecl()->getName() << "')";
84  SourceLocation L = IV->getLocation();
85  Ranges.push_back(SourceRange(L, L));
86  break;
87  }
88  }
89 }
90 
91 static const Expr *getDereferenceExpr(const Stmt *S, bool IsBind=false){
92  const Expr *E = nullptr;
93 
94  // Walk through lvalue casts to get the original expression
95  // that syntactically caused the load.
96  if (const Expr *expr = dyn_cast<Expr>(S))
97  E = expr->IgnoreParenLValueCasts();
98 
99  if (IsBind) {
100  const VarDecl *VD;
101  const Expr *Init;
102  std::tie(VD, Init) = parseAssignment(S);
103  if (VD && Init)
104  E = Init;
105  }
106  return E;
107 }
108 
109 static bool suppressReport(const Expr *E) {
110  // Do not report dereferences on memory in non-default address spaces.
111  return E->getType().getQualifiers().hasAddressSpace();
112 }
113 
114 static bool isDeclRefExprToReference(const Expr *E) {
115  if (const auto *DRE = dyn_cast<DeclRefExpr>(E))
116  return DRE->getDecl()->getType()->isReferenceType();
117  return false;
118 }
119 
120 void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S,
121  CheckerContext &C) const {
122  // Generate an error node.
123  ExplodedNode *N = C.generateErrorNode(State);
124  if (!N)
125  return;
126 
127  // We know that 'location' cannot be non-null. This is what
128  // we call an "explicit" null dereference.
129  if (!BT_null)
130  BT_null.reset(new BuiltinBug(this, "Dereference of null pointer"));
131 
132  SmallString<100> buf;
133  llvm::raw_svector_ostream os(buf);
134 
136 
137  switch (S->getStmtClass()) {
138  case Stmt::ArraySubscriptExprClass: {
139  os << "Array access";
140  const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S);
141  AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(),
142  State.get(), N->getLocationContext());
143  os << " results in a null pointer dereference";
144  break;
145  }
146  case Stmt::OMPArraySectionExprClass: {
147  os << "Array access";
148  const OMPArraySectionExpr *AE = cast<OMPArraySectionExpr>(S);
149  AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(),
150  State.get(), N->getLocationContext());
151  os << " results in a null pointer dereference";
152  break;
153  }
154  case Stmt::UnaryOperatorClass: {
155  os << "Dereference of null pointer";
156  const UnaryOperator *U = cast<UnaryOperator>(S);
157  AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(),
158  State.get(), N->getLocationContext(), true);
159  break;
160  }
161  case Stmt::MemberExprClass: {
162  const MemberExpr *M = cast<MemberExpr>(S);
163  if (M->isArrow() || isDeclRefExprToReference(M->getBase())) {
164  os << "Access to field '" << M->getMemberNameInfo()
165  << "' results in a dereference of a null pointer";
166  AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(),
167  State.get(), N->getLocationContext(), true);
168  }
169  break;
170  }
171  case Stmt::ObjCIvarRefExprClass: {
172  const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(S);
173  os << "Access to instance variable '" << *IV->getDecl()
174  << "' results in a dereference of a null pointer";
175  AddDerefSource(os, Ranges, IV->getBase()->IgnoreParenCasts(),
176  State.get(), N->getLocationContext(), true);
177  break;
178  }
179  default:
180  break;
181  }
182 
183  auto report = llvm::make_unique<BugReport>(
184  *BT_null, buf.empty() ? BT_null->getDescription() : StringRef(buf), N);
185 
186  bugreporter::trackExpressionValue(N, bugreporter::getDerefExpr(S), *report);
187 
189  I = Ranges.begin(), E = Ranges.end(); I!=E; ++I)
190  report->addRange(*I);
191 
192  C.emitReport(std::move(report));
193 }
194 
195 void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
196  CheckerContext &C) const {
197  // Check for dereference of an undefined value.
198  if (l.isUndef()) {
199  if (ExplodedNode *N = C.generateErrorNode()) {
200  if (!BT_undef)
201  BT_undef.reset(
202  new BuiltinBug(this, "Dereference of undefined pointer value"));
203 
204  auto report =
205  llvm::make_unique<BugReport>(*BT_undef, BT_undef->getDescription(), N);
206  bugreporter::trackExpressionValue(N, bugreporter::getDerefExpr(S), *report);
207  C.emitReport(std::move(report));
208  }
209  return;
210  }
211 
212  DefinedOrUnknownSVal location = l.castAs<DefinedOrUnknownSVal>();
213 
214  // Check for null dereferences.
215  if (!location.getAs<Loc>())
216  return;
217 
218  ProgramStateRef state = C.getState();
219 
220  ProgramStateRef notNullState, nullState;
221  std::tie(notNullState, nullState) = state->assume(location);
222 
223  // The explicit NULL case.
224  if (nullState) {
225  if (!notNullState) {
226  const Expr *expr = getDereferenceExpr(S);
227  if (!suppressReport(expr)) {
228  reportBug(nullState, expr, C);
229  return;
230  }
231  }
232 
233  // Otherwise, we have the case where the location could either be
234  // null or not-null. Record the error node as an "implicit" null
235  // dereference.
236  if (ExplodedNode *N = C.generateSink(nullState, C.getPredecessor())) {
237  ImplicitNullDerefEvent event = {l, isLoad, N, &C.getBugReporter(),
238  /*IsDirectDereference=*/true};
239  dispatchEvent(event);
240  }
241  }
242 
243  // From this point forward, we know that the location is not null.
244  C.addTransition(notNullState);
245 }
246 
247 void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S,
248  CheckerContext &C) const {
249  // If we're binding to a reference, check if the value is known to be null.
250  if (V.isUndef())
251  return;
252 
253  const MemRegion *MR = L.getAsRegion();
254  const TypedValueRegion *TVR = dyn_cast_or_null<TypedValueRegion>(MR);
255  if (!TVR)
256  return;
257 
258  if (!TVR->getValueType()->isReferenceType())
259  return;
260 
261  ProgramStateRef State = C.getState();
262 
263  ProgramStateRef StNonNull, StNull;
264  std::tie(StNonNull, StNull) = State->assume(V.castAs<DefinedOrUnknownSVal>());
265 
266  if (StNull) {
267  if (!StNonNull) {
268  const Expr *expr = getDereferenceExpr(S, /*IsBind=*/true);
269  if (!suppressReport(expr)) {
270  reportBug(StNull, expr, C);
271  return;
272  }
273  }
274 
275  // At this point the value could be either null or non-null.
276  // Record this as an "implicit" null dereference.
277  if (ExplodedNode *N = C.generateSink(StNull, C.getPredecessor())) {
278  ImplicitNullDerefEvent event = {V, /*isLoad=*/true, N,
279  &C.getBugReporter(),
280  /*IsDirectDereference=*/true};
281  dispatchEvent(event);
282  }
283  }
284 
285  // Unlike a regular null dereference, initializing a reference with a
286  // dereferenced null pointer does not actually cause a runtime exception in
287  // Clang's implementation of references.
288  //
289  // int &r = *p; // safe??
290  // if (p != NULL) return; // uh-oh
291  // r = 5; // trap here
292  //
293  // The standard says this is invalid as soon as we try to create a "null
294  // reference" (there is no such thing), but turning this into an assumption
295  // that 'p' is never null will not match our actual runtime behavior.
296  // So we do not record this assumption, allowing us to warn on the last line
297  // of this example.
298  //
299  // We do need to add a transition because we may have generated a sink for
300  // the "implicit" null dereference.
301  C.addTransition(State, this);
302 }
303 
304 void ento::registerDereferenceChecker(CheckerManager &mgr) {
305  mgr.registerChecker<DereferenceChecker>();
306 }
Stmt - This represents one statement.
Definition: Stmt.h:66
Expr * getBase() const
Definition: Expr.h:2686
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
Represents a variable declaration or definition.
Definition: Decl.h:812
const internal::VariadicDynCastAllOfMatcher< Stmt, Expr > expr
Matches expressions.
LineState State
static bool suppressReport(const Expr *E)
i32 captured_struct **param SharedsTy A type which contains references the shared variables *param Shareds Context with the list of shared variables from the p *TaskFunction *param Data Additional data for task generation like final * state
bool hasAddressSpace() const
Definition: Type.h:355
bool isArrow() const
Definition: Expr.h:2793
Expr * IgnoreParenCasts() LLVM_READONLY
IgnoreParenCasts - Ignore parentheses and casts.
Definition: Expr.cpp:2554
ObjCIvarDecl * getDecl()
Definition: ExprObjC.h:543
OpenMP 4.0 [2.4, Array Sections].
Definition: ExprOpenMP.h:45
std::pair< const clang::VarDecl *, const clang::Expr * > parseAssignment(const Stmt *S)
static bool isDeclRefExprToReference(const Expr *E)
This represents one expression.
Definition: Expr.h:106
QualType getType() const
Definition: Expr.h:128
UnaryOperator - This represents the unary-expression&#39;s (except sizeof and alignof), the postinc/postdec operators from postfix-expression, and various extensions.
Definition: Expr.h:1907
SourceLocation getMemberLoc() const
getMemberLoc - Return the location of the "member", in X->F, it is the location of &#39;F&#39;...
Definition: Expr.h:2798
ValueDecl * getDecl()
Definition: Expr.h:1125
Encodes a location in the source.
Expr * getSubExpr() const
Definition: Expr.h:1937
static const Expr * getDereferenceExpr(const Stmt *S, bool IsBind=false)
Dataflow Directional Tag Classes.
DeclarationNameInfo getMemberNameInfo() const
Retrieve the member declaration name info.
Definition: Expr.h:2786
StmtClass getStmtClass() const
Definition: Stmt.h:809
ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
Definition: Expr.h:2323
SourceLocation getLocation() const
Definition: ExprObjC.h:556
Expr * IgnoreParenLValueCasts() LLVM_READONLY
Ignore parentheses and lvalue casts.
Definition: Expr.cpp:2609
const Expr * getBase() const
Definition: ExprObjC.h:547
ObjCIvarRefExpr - A reference to an ObjC instance variable.
Definition: ExprObjC.h:513
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition: Expr.h:2601
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
Definition: Type.h:6085
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:276
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition: Decl.h:275
A reference to a declared variable, function, enum, etc.
Definition: Expr.h:1042
A trivial tuple used to represent a source range.
Expr * IgnoreParens() LLVM_READONLY
IgnoreParens - Ignore parentheses.
Definition: Expr.cpp:2523
Expr * getBase()
An array section can be written only as Base[LowerBound:Length].
Definition: ExprOpenMP.h:82