clang  6.0.0svn
NonNullParamChecker.cpp
Go to the documentation of this file.
1 //===--- NonNullParamChecker.cpp - Undefined arguments 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 NonNullParamChecker, which checks for arguments expected not to
11 // be null due to:
12 // - the corresponding parameters being declared to have nonnull attribute
13 // - the corresponding parameters being references; since the call would form
14 // a reference to a null pointer
15 //
16 //===----------------------------------------------------------------------===//
17 
18 #include "ClangSACheckers.h"
19 #include "clang/AST/Attr.h"
25 
26 using namespace clang;
27 using namespace ento;
28 
29 namespace {
30 class NonNullParamChecker
31  : public Checker< check::PreCall, EventDispatcher<ImplicitNullDerefEvent> > {
32  mutable std::unique_ptr<BugType> BTAttrNonNull;
33  mutable std::unique_ptr<BugType> BTNullRefArg;
34 
35 public:
36 
37  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
38 
39  std::unique_ptr<BugReport>
40  genReportNullAttrNonNull(const ExplodedNode *ErrorN, const Expr *ArgE) const;
41  std::unique_ptr<BugReport>
42  genReportReferenceToNullPointer(const ExplodedNode *ErrorN,
43  const Expr *ArgE) const;
44 };
45 } // end anonymous namespace
46 
47 void NonNullParamChecker::checkPreCall(const CallEvent &Call,
48  CheckerContext &C) const {
49  const Decl *FD = Call.getDecl();
50  if (!FD)
51  return;
52 
53  // Merge all non-null attributes
54  unsigned NumArgs = Call.getNumArgs();
55  llvm::SmallBitVector AttrNonNull(NumArgs);
56  for (const auto *NonNull : FD->specific_attrs<NonNullAttr>()) {
57  if (!NonNull->args_size()) {
58  AttrNonNull.set(0, NumArgs);
59  break;
60  }
61  for (unsigned Val : NonNull->args()) {
62  if (Val >= NumArgs)
63  continue;
64  AttrNonNull.set(Val);
65  }
66  }
67 
69 
71  TyE = Call.param_type_end();
72 
73  for (unsigned idx = 0; idx < NumArgs; ++idx) {
74 
75  // Check if the parameter is a reference. We want to report when reference
76  // to a null pointer is passed as a parameter.
77  bool haveRefTypeParam = false;
78  if (TyI != TyE) {
79  haveRefTypeParam = (*TyI)->isReferenceType();
80  TyI++;
81  }
82 
83  bool haveAttrNonNull = AttrNonNull[idx];
84  if (!haveAttrNonNull) {
85  // Check if the parameter is also marked 'nonnull'.
86  ArrayRef<ParmVarDecl*> parms = Call.parameters();
87  if (idx < parms.size())
88  haveAttrNonNull = parms[idx]->hasAttr<NonNullAttr>();
89  }
90 
91  if (!haveRefTypeParam && !haveAttrNonNull)
92  continue;
93 
94  // If the value is unknown or undefined, we can't perform this check.
95  const Expr *ArgE = Call.getArgExpr(idx);
96  SVal V = Call.getArgSVal(idx);
98  if (!DV)
99  continue;
100 
101  // Process the case when the argument is not a location.
102  assert(!haveRefTypeParam || DV->getAs<Loc>());
103 
104  if (haveAttrNonNull && !DV->getAs<Loc>()) {
105  // If the argument is a union type, we want to handle a potential
106  // transparent_union GCC extension.
107  if (!ArgE)
108  continue;
109 
110  QualType T = ArgE->getType();
111  const RecordType *UT = T->getAsUnionType();
112  if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>())
113  continue;
114 
116  DV->getAs<nonloc::CompoundVal>()) {
117  nonloc::CompoundVal::iterator CSV_I = CSV->begin();
118  assert(CSV_I != CSV->end());
119  V = *CSV_I;
120  DV = V.getAs<DefinedSVal>();
121  assert(++CSV_I == CSV->end());
122  // FIXME: Handle (some_union){ some_other_union_val }, which turns into
123  // a LazyCompoundVal inside a CompoundVal.
124  if (!V.getAs<Loc>())
125  continue;
126  // Retrieve the corresponding expression.
127  if (const CompoundLiteralExpr *CE = dyn_cast<CompoundLiteralExpr>(ArgE))
128  if (const InitListExpr *IE =
129  dyn_cast<InitListExpr>(CE->getInitializer()))
130  ArgE = dyn_cast<Expr>(*(IE->begin()));
131 
132  } else {
133  // FIXME: Handle LazyCompoundVals?
134  continue;
135  }
136  }
137 
139  ProgramStateRef stateNotNull, stateNull;
140  std::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
141 
142  if (stateNull) {
143  if (!stateNotNull) {
144  // Generate an error node. Check for a null node in case
145  // we cache out.
146  if (ExplodedNode *errorNode = C.generateErrorNode(stateNull)) {
147 
148  std::unique_ptr<BugReport> R;
149  if (haveAttrNonNull)
150  R = genReportNullAttrNonNull(errorNode, ArgE);
151  else if (haveRefTypeParam)
152  R = genReportReferenceToNullPointer(errorNode, ArgE);
153 
154  // Highlight the range of the argument that was null.
155  R->addRange(Call.getArgSourceRange(idx));
156 
157  // Emit the bug report.
158  C.emitReport(std::move(R));
159  }
160 
161  // Always return. Either we cached out or we just emitted an error.
162  return;
163  }
164  if (ExplodedNode *N = C.generateSink(stateNull, C.getPredecessor())) {
165  ImplicitNullDerefEvent event = {
166  V, false, N, &C.getBugReporter(),
167  /*IsDirectDereference=*/haveRefTypeParam};
168  dispatchEvent(event);
169  }
170  }
171 
172  // If a pointer value passed the check we should assume that it is
173  // indeed not null from this point forward.
174  assert(stateNotNull);
175  state = stateNotNull;
176  }
177 
178  // If we reach here all of the arguments passed the nonnull check.
179  // If 'state' has been updated generated a new node.
180  C.addTransition(state);
181 }
182 
183 std::unique_ptr<BugReport>
184 NonNullParamChecker::genReportNullAttrNonNull(const ExplodedNode *ErrorNode,
185  const Expr *ArgE) const {
186  // Lazily allocate the BugType object if it hasn't already been
187  // created. Ownership is transferred to the BugReporter object once
188  // the BugReport is passed to 'EmitWarning'.
189  if (!BTAttrNonNull)
190  BTAttrNonNull.reset(new BugType(
191  this, "Argument with 'nonnull' attribute passed null", "API"));
192 
193  auto R = llvm::make_unique<BugReport>(
194  *BTAttrNonNull,
195  "Null pointer passed as an argument to a 'nonnull' parameter", ErrorNode);
196  if (ArgE)
197  bugreporter::trackNullOrUndefValue(ErrorNode, ArgE, *R);
198 
199  return R;
200 }
201 
202 std::unique_ptr<BugReport> NonNullParamChecker::genReportReferenceToNullPointer(
203  const ExplodedNode *ErrorNode, const Expr *ArgE) const {
204  if (!BTNullRefArg)
205  BTNullRefArg.reset(new BuiltinBug(this, "Dereference of null pointer"));
206 
207  auto R = llvm::make_unique<BugReport>(
208  *BTNullRefArg, "Forming reference to null pointer", ErrorNode);
209  if (ArgE) {
210  const Expr *ArgEDeref = bugreporter::getDerefExpr(ArgE);
211  if (!ArgEDeref)
212  ArgEDeref = ArgE;
214  ArgEDeref,
215  *R);
216  }
217  return R;
218 
219 }
220 
221 void ento::registerNonNullParamChecker(CheckerManager &mgr) {
222  mgr.registerChecker<NonNullParamChecker>();
223 }
const Expr * getDerefExpr(const Stmt *S)
Given that expression S represents a pointer that would be dereferenced, try to find a sub-expression...
A (possibly-)qualified type.
Definition: Type.h:653
ExplodedNode * generateErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph).
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
const RecordType * getAsUnionType() const
NOTE: getAs*ArrayType are methods on ASTContext.
Definition: Type.cpp:491
CompoundLiteralExpr - [C99 6.5.2.5].
Definition: Expr.h:2637
ExplodedNode * getPredecessor()
Returns the previous node in the exploded graph, which includes the state of the program before the c...
llvm::mapped_iterator< ArrayRef< ParmVarDecl * >::iterator, GetTypeFn > param_type_iterator
Definition: CallEvent.h:399
param_type_iterator param_type_end() const
Definition: CallEvent.h:410
virtual const Expr * getArgExpr(unsigned Index) const
Returns the expression associated with a given argument.
Definition: CallEvent.h:275
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()
Describes an C or C++ initializer list.
Definition: Expr.h:3872
Values of this type can never be null.
param_type_iterator param_type_begin() const
Returns an iterator over the types of the call&#39;s formal parameters.
Definition: CallEvent.h:406
We dereferenced a location that may be null.
Definition: Checker.h:536
bool hasAttr() const
Definition: DeclBase.h:535
ProgramStatePair assumeDual(ProgramStateRef State, DefinedSVal Cond)
Returns a pair of states (StTrue, StFalse) where the given condition is assumed to be true or false...
llvm::ImmutableList< SVal >::iterator iterator
Definition: SVals.h:438
Expr - This represents one expression.
Definition: Expr.h:106
virtual ArrayRef< ParmVarDecl * > parameters() const =0
Return call&#39;s formal parameters.
const FunctionProtoType * T
QualType getType() const
Definition: Expr.h:128
virtual const Decl * getDecl() const
Returns the declaration of the function or method that will be called.
Definition: CallEvent.h:205
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
ConstraintManager & getConstraintManager()
RecordDecl * getDecl() const
Definition: Type.h:3988
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
CHECKER * registerChecker()
Used to register checkers.
ExplodedNode * generateSink(ProgramStateRef State, ExplodedNode *Pred, const ProgramPointTag *Tag=nullptr)
Generate a sink node.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
Definition: SVals.h:63
Dataflow Directional Tag Classes.
virtual SourceRange getArgSourceRange(unsigned Index) const
Returns the source range for errors associated with this argument.
Definition: CallEvent.cpp:235
Represents an abstract call to a function or method along a particular path.
Definition: CallEvent.h:140
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
Definition: Type.h:3978
const ProgramStateRef & getState() const
llvm::iterator_range< specific_attr_iterator< T > > specific_attrs() const
Definition: DeclBase.h:517
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.
virtual unsigned getNumArgs() const =0
Returns the number of arguments (explicit and implicit).
virtual SVal getArgSVal(unsigned Index) const
Returns the value of a given argument at the time of the call.
Definition: CallEvent.cpp:228