clang  6.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 void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S,
115  CheckerContext &C) const {
116  // Generate an error node.
117  ExplodedNode *N = C.generateErrorNode(State);
118  if (!N)
119  return;
120 
121  // We know that 'location' cannot be non-null. This is what
122  // we call an "explicit" null dereference.
123  if (!BT_null)
124  BT_null.reset(new BuiltinBug(this, "Dereference of null pointer"));
125 
126  SmallString<100> buf;
127  llvm::raw_svector_ostream os(buf);
128 
130 
131  switch (S->getStmtClass()) {
132  case Stmt::ArraySubscriptExprClass: {
133  os << "Array access";
134  const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S);
135  AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(),
136  State.get(), N->getLocationContext());
137  os << " results in a null pointer dereference";
138  break;
139  }
140  case Stmt::OMPArraySectionExprClass: {
141  os << "Array access";
142  const OMPArraySectionExpr *AE = cast<OMPArraySectionExpr>(S);
143  AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(),
144  State.get(), N->getLocationContext());
145  os << " results in a null pointer dereference";
146  break;
147  }
148  case Stmt::UnaryOperatorClass: {
149  os << "Dereference of null pointer";
150  const UnaryOperator *U = cast<UnaryOperator>(S);
151  AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(),
152  State.get(), N->getLocationContext(), true);
153  break;
154  }
155  case Stmt::MemberExprClass: {
156  const MemberExpr *M = cast<MemberExpr>(S);
158  os << "Access to field '" << M->getMemberNameInfo()
159  << "' results in a dereference of a null pointer";
160  AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(),
161  State.get(), N->getLocationContext(), true);
162  }
163  break;
164  }
165  case Stmt::ObjCIvarRefExprClass: {
166  const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(S);
167  os << "Access to instance variable '" << *IV->getDecl()
168  << "' results in a dereference of a null pointer";
169  AddDerefSource(os, Ranges, IV->getBase()->IgnoreParenCasts(),
170  State.get(), N->getLocationContext(), true);
171  break;
172  }
173  default:
174  break;
175  }
176 
177  auto report = llvm::make_unique<BugReport>(
178  *BT_null, buf.empty() ? BT_null->getDescription() : StringRef(buf), N);
179 
181 
183  I = Ranges.begin(), E = Ranges.end(); I!=E; ++I)
184  report->addRange(*I);
185 
186  C.emitReport(std::move(report));
187 }
188 
189 void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
190  CheckerContext &C) const {
191  // Check for dereference of an undefined value.
192  if (l.isUndef()) {
193  if (ExplodedNode *N = C.generateErrorNode()) {
194  if (!BT_undef)
195  BT_undef.reset(
196  new BuiltinBug(this, "Dereference of undefined pointer value"));
197 
198  auto report =
199  llvm::make_unique<BugReport>(*BT_undef, BT_undef->getDescription(), N);
201  *report);
202  C.emitReport(std::move(report));
203  }
204  return;
205  }
206 
208 
209  // Check for null dereferences.
210  if (!location.getAs<Loc>())
211  return;
212 
213  ProgramStateRef state = C.getState();
214 
215  ProgramStateRef notNullState, nullState;
216  std::tie(notNullState, nullState) = state->assume(location);
217 
218  // The explicit NULL case.
219  if (nullState) {
220  if (!notNullState) {
221  const Expr *expr = getDereferenceExpr(S);
222  if (!suppressReport(expr)) {
223  reportBug(nullState, expr, C);
224  return;
225  }
226  }
227 
228  // Otherwise, we have the case where the location could either be
229  // null or not-null. Record the error node as an "implicit" null
230  // dereference.
231  if (ExplodedNode *N = C.generateSink(nullState, C.getPredecessor())) {
232  ImplicitNullDerefEvent event = {l, isLoad, N, &C.getBugReporter(),
233  /*IsDirectDereference=*/true};
234  dispatchEvent(event);
235  }
236  }
237 
238  // From this point forward, we know that the location is not null.
239  C.addTransition(notNullState);
240 }
241 
242 void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S,
243  CheckerContext &C) const {
244  // If we're binding to a reference, check if the value is known to be null.
245  if (V.isUndef())
246  return;
247 
248  const MemRegion *MR = L.getAsRegion();
249  const TypedValueRegion *TVR = dyn_cast_or_null<TypedValueRegion>(MR);
250  if (!TVR)
251  return;
252 
253  if (!TVR->getValueType()->isReferenceType())
254  return;
255 
256  ProgramStateRef State = C.getState();
257 
258  ProgramStateRef StNonNull, StNull;
259  std::tie(StNonNull, StNull) = State->assume(V.castAs<DefinedOrUnknownSVal>());
260 
261  if (StNull) {
262  if (!StNonNull) {
263  const Expr *expr = getDereferenceExpr(S, /*IsBind=*/true);
264  if (!suppressReport(expr)) {
265  reportBug(StNull, expr, C);
266  return;
267  }
268  }
269 
270  // At this point the value could be either null or non-null.
271  // Record this as an "implicit" null dereference.
272  if (ExplodedNode *N = C.generateSink(StNull, C.getPredecessor())) {
273  ImplicitNullDerefEvent event = {V, /*isLoad=*/true, N,
274  &C.getBugReporter(),
275  /*IsDirectDereference=*/true};
276  dispatchEvent(event);
277  }
278  }
279 
280  // Unlike a regular null dereference, initializing a reference with a
281  // dereferenced null pointer does not actually cause a runtime exception in
282  // Clang's implementation of references.
283  //
284  // int &r = *p; // safe??
285  // if (p != NULL) return; // uh-oh
286  // r = 5; // trap here
287  //
288  // The standard says this is invalid as soon as we try to create a "null
289  // reference" (there is no such thing), but turning this into an assumption
290  // that 'p' is never null will not match our actual runtime behavior.
291  // So we do not record this assumption, allowing us to warn on the last line
292  // of this example.
293  //
294  // We do need to add a transition because we may have generated a sink for
295  // the "implicit" null dereference.
296  C.addTransition(State, this);
297 }
298 
299 void ento::registerDereferenceChecker(CheckerManager &mgr) {
300  mgr.registerChecker<DereferenceChecker>();
301 }
TypedValueRegion - An abstract class representing regions having a typed value.
Definition: MemRegion.h:511
const Expr * getDerefExpr(const Stmt *S)
Given that expression S represents a pointer that would be dereferenced, try to find a sub-expression...
MemRegion - The root abstract class for all memory regions.
Definition: MemRegion.h:79
ExplodedNode * generateErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
Stmt - This represents one statement.
Definition: Stmt.h:66
Expr * getBase() const
Definition: Expr.h:2477
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph).
virtual QualType getValueType() const =0
VarDecl - An instance of this class is created to represent a variable declaration or definition...
Definition: Decl.h:807
const internal::VariadicDynCastAllOfMatcher< Stmt, Expr > expr
Matches expressions.
ExplodedNode * getPredecessor()
Returns the previous node in the exploded graph, which includes the state of the program before the c...
LineState State
static bool suppressReport(const Expr *E)
bool isReferenceType() const
Definition: Type.h:5956
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
BugReporter & getBugReporter()
bool hasAddressSpace() const
Definition: Type.h:366
const LocationContext * getLocationContext() const
bool isArrow() const
Definition: Expr.h:2582
Expr * IgnoreParenCasts() LLVM_READONLY
IgnoreParenCasts - Ignore parentheses and casts.
Definition: Expr.cpp:2463
We dereferenced a location that may be null.
Definition: Checker.h:536
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)
ProgramState - This class encapsulates:
Definition: ProgramState.h:74
Expr - 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:1717
SourceLocation getMemberLoc() const
getMemberLoc - Return the location of the "member", in X->F, it is the location of &#39;F&#39;...
Definition: Expr.h:2587
ValueDecl * getDecl()
Definition: Expr.h:1041
Optional< T > getAs() const
Convert to the specified SVal type, returning None if this SVal is not of the desired type...
Definition: SVals.h:100
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
CHECKER * registerChecker()
Used to register checkers.
Encodes a location in the source.
ExplodedNode * generateSink(ProgramStateRef State, ExplodedNode *Pred, const ProgramPointTag *Tag=nullptr)
Generate a sink node.
Expr * getSubExpr() const
Definition: Expr.h:1744
const MemRegion * getAsRegion() const
Definition: SVals.cpp:140
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
Definition: SVals.h:63
static const Expr * getDereferenceExpr(const Stmt *S, bool IsBind=false)
bool isDeclRefExprToReference(const Expr *E)
Dataflow Directional Tag Classes.
DeclarationNameInfo getMemberNameInfo() const
Retrieve the member declaration name info.
Definition: Expr.h:2575
StmtClass getStmtClass() const
Definition: Stmt.h:378
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
Definition: SVals.h:92
ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
Definition: Expr.h:2121
const ProgramStateRef & getState() const
SourceLocation getLocation() const
Definition: ExprObjC.h:556
Expr * IgnoreParenLValueCasts() LLVM_READONLY
Ignore parentheses and lvalue casts.
Definition: Expr.cpp:2510
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:2387
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
Definition: Type.h:5747
bool trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, BugReport &R, bool IsArg=false, bool EnableNullFPSuppression=true)
Attempts to add visitors to trace a null or undefined value back to its point of origin, whether it is a symbol constrained to null or an explicit assignment.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:265
bool isUndef() const
Definition: SVals.h:129
StringRef getName() const
getName - Get the name of identifier for this declaration as a StringRef.
Definition: Decl.h:270
A reference to a declared variable, function, enum, etc.
Definition: Expr.h:956
A trivial tuple used to represent a source range.
Expr * IgnoreParens() LLVM_READONLY
IgnoreParens - Ignore parentheses.
Definition: Expr.cpp:2432
Expr * getBase()
An array section can be written only as Base[LowerBound:Length].
Definition: ExprOpenMP.h:82