clang  3.7.0
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 > {
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 
68  ProgramStateRef state = C.getState();
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 paramter.
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 && !stateNotNull) {
143  // Generate an error node. Check for a null node in case
144  // we cache out.
145  if (ExplodedNode *errorNode = C.generateSink(stateNull)) {
146 
147  std::unique_ptr<BugReport> R;
148  if (haveAttrNonNull)
149  R = genReportNullAttrNonNull(errorNode, ArgE);
150  else if (haveRefTypeParam)
151  R = genReportReferenceToNullPointer(errorNode, ArgE);
152 
153  // Highlight the range of the argument that was null.
154  R->addRange(Call.getArgSourceRange(idx));
155 
156  // Emit the bug report.
157  C.emitReport(std::move(R));
158  }
159 
160  // Always return. Either we cached out or we just emitted an error.
161  return;
162  }
163 
164  // If a pointer value passed the check we should assume that it is
165  // indeed not null from this point forward.
166  assert(stateNotNull);
167  state = stateNotNull;
168  }
169 
170  // If we reach here all of the arguments passed the nonnull check.
171  // If 'state' has been updated generated a new node.
172  C.addTransition(state);
173 }
174 
175 std::unique_ptr<BugReport>
176 NonNullParamChecker::genReportNullAttrNonNull(const ExplodedNode *ErrorNode,
177  const Expr *ArgE) const {
178  // Lazily allocate the BugType object if it hasn't already been
179  // created. Ownership is transferred to the BugReporter object once
180  // the BugReport is passed to 'EmitWarning'.
181  if (!BTAttrNonNull)
182  BTAttrNonNull.reset(new BugType(
183  this, "Argument with 'nonnull' attribute passed null", "API"));
184 
185  auto R = llvm::make_unique<BugReport>(
186  *BTAttrNonNull,
187  "Null pointer passed as an argument to a 'nonnull' parameter", ErrorNode);
188  if (ArgE)
189  bugreporter::trackNullOrUndefValue(ErrorNode, ArgE, *R);
190 
191  return R;
192 }
193 
194 std::unique_ptr<BugReport> NonNullParamChecker::genReportReferenceToNullPointer(
195  const ExplodedNode *ErrorNode, const Expr *ArgE) const {
196  if (!BTNullRefArg)
197  BTNullRefArg.reset(new BuiltinBug(this, "Dereference of null pointer"));
198 
199  auto R = llvm::make_unique<BugReport>(
200  *BTNullRefArg, "Forming reference to null pointer", ErrorNode);
201  if (ArgE) {
202  const Expr *ArgEDeref = bugreporter::getDerefExpr(ArgE);
203  if (!ArgEDeref)
204  ArgEDeref = ArgE;
206  ArgEDeref,
207  *R);
208  }
209  return R;
210 
211 }
212 
213 void ento::registerNonNullParamChecker(CheckerManager &mgr) {
214  mgr.registerChecker<NonNullParamChecker>();
215 }
virtual SVal getArgSVal(unsigned Index) const
Returns the value of a given argument at the time of the call.
Definition: CallEvent.cpp:195
const Expr * getDerefExpr(const Stmt *S)
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph). Uses the default CheckerContex...
param_type_iterator param_type_end() const
Definition: CallEvent.h:367
bool hasAttr() const
Definition: DeclBase.h:487
const RecordType * getAsUnionType() const
NOTE: getAs*ArrayType are methods on ASTContext.
Definition: Type.cpp:449
Describes an C or C++ initializer list.
Definition: Expr.h:3759
RecordDecl * getDecl() const
Definition: Type.h:3527
Values of this type can never be null.
virtual SourceRange getArgSourceRange(unsigned Index) const
Returns the source range for errors associated with this argument.
Definition: CallEvent.cpp:202
ProgramStatePair assumeDual(ProgramStateRef State, DefinedSVal Cond)
ExplodedNode * generateSink(ProgramStateRef State=nullptr, ExplodedNode *Pred=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a sink node. Generating a sink stops exploration of the given path.
llvm::ImmutableList< SVal >::iterator iterator
Definition: SVals.h:420
virtual const Expr * getArgExpr(unsigned Index) const
Returns the expression associated with a given argument. May be null if this expression does not appe...
Definition: CallEvent.h:240
virtual ArrayRef< ParmVarDecl * > parameters() const =0
const ProgramStateRef & getState() const
Optional< T > getAs() const
Convert to the specified SVal type, returning None if this SVal is not of the desired type...
Definition: SVals.h:86
param_type_iterator param_type_begin() const
Definition: CallEvent.h:362
ConstraintManager & getConstraintManager()
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
CHECKER * registerChecker()
Used to register checkers.
virtual const Decl * getDecl() const
Returns the declaration of the function or method that will be called. May be null.
Definition: CallEvent.h:177
QualType getType() const
Definition: Expr.h:125
Represents an abstract call to a function or method along a particular path.
Definition: CallEvent.h:113
llvm::iterator_range< specific_attr_iterator< T > > specific_attrs() const
Definition: DeclBase.h:470
bool trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, BugReport &R, bool IsArg=false, bool EnableNullFPSuppression=true)
virtual unsigned getNumArgs() const =0
Returns the number of arguments (explicit and implicit).
llvm::mapped_iterator< ArrayRef< ParmVarDecl * >::iterator, get_type_fun > param_type_iterator
Definition: CallEvent.h:355