clang  12.0.0git
NonNullParamChecker.cpp
Go to the documentation of this file.
1 //===--- NonNullParamChecker.cpp - Undefined arguments checker -*- C++ -*--===//
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 NonNullParamChecker, which checks for arguments expected not to
10 // be null due to:
11 // - the corresponding parameters being declared to have nonnull attribute
12 // - the corresponding parameters being references; since the call would form
13 // a reference to a null pointer
14 //
15 //===----------------------------------------------------------------------===//
16 
17 #include "clang/AST/Attr.h"
18 #include "clang/Analysis/AnyCall.h"
25 #include "llvm/ADT/StringExtras.h"
26 
27 using namespace clang;
28 using namespace ento;
29 
30 namespace {
31 class NonNullParamChecker
32  : public Checker<check::PreCall, check::BeginFunction,
33  EventDispatcher<ImplicitNullDerefEvent>> {
34  mutable std::unique_ptr<BugType> BTAttrNonNull;
35  mutable std::unique_ptr<BugType> BTNullRefArg;
36 
37 public:
38  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
39  void checkBeginFunction(CheckerContext &C) const;
40 
41  std::unique_ptr<PathSensitiveBugReport>
42  genReportNullAttrNonNull(const ExplodedNode *ErrorN, const Expr *ArgE,
43  unsigned IdxOfArg) const;
44  std::unique_ptr<PathSensitiveBugReport>
45  genReportReferenceToNullPointer(const ExplodedNode *ErrorN,
46  const Expr *ArgE) const;
47 };
48 
49 template <class CallType>
50 void setBitsAccordingToFunctionAttributes(const CallType &Call,
51  llvm::SmallBitVector &AttrNonNull) {
52  const Decl *FD = Call.getDecl();
53 
54  for (const auto *NonNull : FD->specific_attrs<NonNullAttr>()) {
55  if (!NonNull->args_size()) {
56  // Lack of attribute parameters means that all of the parameters are
57  // implicitly marked as non-null.
58  AttrNonNull.set();
59  break;
60  }
61 
62  for (const ParamIdx &Idx : NonNull->args()) {
63  // 'nonnull' attribute's parameters are 1-based and should be adjusted to
64  // match actual AST parameter/argument indices.
65  unsigned IdxAST = Idx.getASTIndex();
66  if (IdxAST >= AttrNonNull.size())
67  continue;
68  AttrNonNull.set(IdxAST);
69  }
70  }
71 }
72 
73 template <class CallType>
74 void setBitsAccordingToParameterAttributes(const CallType &Call,
75  llvm::SmallBitVector &AttrNonNull) {
76  for (const ParmVarDecl *Parameter : Call.parameters()) {
77  unsigned ParameterIndex = Parameter->getFunctionScopeIndex();
78  if (ParameterIndex == AttrNonNull.size())
79  break;
80 
81  if (Parameter->hasAttr<NonNullAttr>())
82  AttrNonNull.set(ParameterIndex);
83  }
84 }
85 
86 template <class CallType>
87 llvm::SmallBitVector getNonNullAttrsImpl(const CallType &Call,
88  unsigned ExpectedSize) {
89  llvm::SmallBitVector AttrNonNull(ExpectedSize);
90 
91  setBitsAccordingToFunctionAttributes(Call, AttrNonNull);
92  setBitsAccordingToParameterAttributes(Call, AttrNonNull);
93 
94  return AttrNonNull;
95 }
96 
97 /// \return Bitvector marking non-null attributes.
98 llvm::SmallBitVector getNonNullAttrs(const CallEvent &Call) {
99  return getNonNullAttrsImpl(Call, Call.getNumArgs());
100 }
101 
102 /// \return Bitvector marking non-null attributes.
103 llvm::SmallBitVector getNonNullAttrs(const AnyCall &Call) {
104  return getNonNullAttrsImpl(Call, Call.param_size());
105 }
106 } // end anonymous namespace
107 
108 void NonNullParamChecker::checkPreCall(const CallEvent &Call,
109  CheckerContext &C) const {
110  if (!Call.getDecl())
111  return;
112 
113  llvm::SmallBitVector AttrNonNull = getNonNullAttrs(Call);
114  unsigned NumArgs = Call.getNumArgs();
115 
116  ProgramStateRef state = C.getState();
117  ArrayRef<ParmVarDecl *> parms = Call.parameters();
118 
119  for (unsigned idx = 0; idx < NumArgs; ++idx) {
120  // For vararg functions, a corresponding parameter decl may not exist.
121  bool HasParam = idx < parms.size();
122 
123  // Check if the parameter is a reference. We want to report when reference
124  // to a null pointer is passed as a parameter.
125  bool HasRefTypeParam =
126  HasParam ? parms[idx]->getType()->isReferenceType() : false;
127  bool ExpectedToBeNonNull = AttrNonNull.test(idx);
128 
129  if (!ExpectedToBeNonNull && !HasRefTypeParam)
130  continue;
131 
132  // If the value is unknown or undefined, we can't perform this check.
133  const Expr *ArgE = Call.getArgExpr(idx);
134  SVal V = Call.getArgSVal(idx);
135  auto DV = V.getAs<DefinedSVal>();
136  if (!DV)
137  continue;
138 
139  assert(!HasRefTypeParam || DV->getAs<Loc>());
140 
141  // Process the case when the argument is not a location.
142  if (ExpectedToBeNonNull && !DV->getAs<Loc>()) {
143  // If the argument is a union type, we want to handle a potential
144  // transparent_union GCC extension.
145  if (!ArgE)
146  continue;
147 
148  QualType T = ArgE->getType();
149  const RecordType *UT = T->getAsUnionType();
150  if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>())
151  continue;
152 
153  auto CSV = DV->getAs<nonloc::CompoundVal>();
154 
155  // FIXME: Handle LazyCompoundVals?
156  if (!CSV)
157  continue;
158 
159  V = *(CSV->begin());
160  DV = V.getAs<DefinedSVal>();
161  assert(++CSV->begin() == CSV->end());
162  // FIXME: Handle (some_union){ some_other_union_val }, which turns into
163  // a LazyCompoundVal inside a CompoundVal.
164  if (!V.getAs<Loc>())
165  continue;
166 
167  // Retrieve the corresponding expression.
168  if (const auto *CE = dyn_cast<CompoundLiteralExpr>(ArgE))
169  if (const auto *IE = dyn_cast<InitListExpr>(CE->getInitializer()))
170  ArgE = dyn_cast<Expr>(*(IE->begin()));
171  }
172 
173  ConstraintManager &CM = C.getConstraintManager();
174  ProgramStateRef stateNotNull, stateNull;
175  std::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
176 
177  // Generate an error node. Check for a null node in case
178  // we cache out.
179  if (stateNull && !stateNotNull) {
180  if (ExplodedNode *errorNode = C.generateErrorNode(stateNull)) {
181 
182  std::unique_ptr<BugReport> R;
183  if (ExpectedToBeNonNull)
184  R = genReportNullAttrNonNull(errorNode, ArgE, idx + 1);
185  else if (HasRefTypeParam)
186  R = genReportReferenceToNullPointer(errorNode, ArgE);
187 
188  // Highlight the range of the argument that was null.
189  R->addRange(Call.getArgSourceRange(idx));
190 
191  // Emit the bug report.
192  C.emitReport(std::move(R));
193  }
194 
195  // Always return. Either we cached out or we just emitted an error.
196  return;
197  }
198 
199  if (stateNull) {
200  if (ExplodedNode *N = C.generateSink(stateNull, C.getPredecessor())) {
201  ImplicitNullDerefEvent event = {
202  V, false, N, &C.getBugReporter(),
203  /*IsDirectDereference=*/HasRefTypeParam};
204  dispatchEvent(event);
205  }
206  }
207 
208  // If a pointer value passed the check we should assume that it is
209  // indeed not null from this point forward.
210  state = stateNotNull;
211  }
212 
213  // If we reach here all of the arguments passed the nonnull check.
214  // If 'state' has been updated generated a new node.
215  C.addTransition(state);
216 }
217 
218 /// We want to trust developer annotations and consider all 'nonnull' parameters
219 /// as non-null indeed. Each marked parameter will get a corresponding
220 /// constraint.
221 ///
222 /// This approach will not only help us to get rid of some false positives, but
223 /// remove duplicates and shorten warning traces as well.
224 ///
225 /// \code
226 /// void foo(int *x) [[gnu::nonnull]] {
227 /// // . . .
228 /// *x = 42; // we don't want to consider this as an error...
229 /// // . . .
230 /// }
231 ///
232 /// foo(nullptr); // ...and report here instead
233 /// \endcode
234 void NonNullParamChecker::checkBeginFunction(CheckerContext &Context) const {
235  // Planned assumption makes sense only for top-level functions.
236  // Inlined functions will get similar constraints as part of 'checkPreCall'.
237  if (!Context.inTopFrame())
238  return;
239 
240  const LocationContext *LocContext = Context.getLocationContext();
241 
242  const Decl *FD = LocContext->getDecl();
243  // AnyCall helps us here to avoid checking for FunctionDecl and ObjCMethodDecl
244  // separately and aggregates interfaces of these classes.
245  auto AbstractCall = AnyCall::forDecl(FD);
246  if (!AbstractCall)
247  return;
248 
249  ProgramStateRef State = Context.getState();
250  llvm::SmallBitVector ParameterNonNullMarks = getNonNullAttrs(*AbstractCall);
251 
252  for (const ParmVarDecl *Parameter : AbstractCall->parameters()) {
253  // 1. Check parameter if it is annotated as non-null
254  if (!ParameterNonNullMarks.test(Parameter->getFunctionScopeIndex()))
255  continue;
256 
257  // 2. Check that parameter is a pointer.
258  // Nonnull attribute can be applied to non-pointers (by default
259  // __attribute__(nonnull) implies "all parameters").
260  if (!Parameter->getType()->isPointerType())
261  continue;
262 
263  Loc ParameterLoc = State->getLValue(Parameter, LocContext);
264  // We never consider top-level function parameters undefined.
265  auto StoredVal =
266  State->getSVal(ParameterLoc).castAs<DefinedOrUnknownSVal>();
267 
268  // 3. Assume that it is indeed non-null
269  if (ProgramStateRef NewState = State->assume(StoredVal, true)) {
270  State = NewState;
271  }
272  }
273 
274  Context.addTransition(State);
275 }
276 
277 std::unique_ptr<PathSensitiveBugReport>
278 NonNullParamChecker::genReportNullAttrNonNull(const ExplodedNode *ErrorNode,
279  const Expr *ArgE,
280  unsigned IdxOfArg) const {
281  // Lazily allocate the BugType object if it hasn't already been
282  // created. Ownership is transferred to the BugReporter object once
283  // the BugReport is passed to 'EmitWarning'.
284  if (!BTAttrNonNull)
285  BTAttrNonNull.reset(new BugType(
286  this, "Argument with 'nonnull' attribute passed null", "API"));
287 
289  llvm::raw_svector_ostream OS(SBuf);
290  OS << "Null pointer passed to "
291  << IdxOfArg << llvm::getOrdinalSuffix(IdxOfArg)
292  << " parameter expecting 'nonnull'";
293 
294  auto R =
295  std::make_unique<PathSensitiveBugReport>(*BTAttrNonNull, SBuf, ErrorNode);
296  if (ArgE)
297  bugreporter::trackExpressionValue(ErrorNode, ArgE, *R);
298 
299  return R;
300 }
301 
302 std::unique_ptr<PathSensitiveBugReport>
303 NonNullParamChecker::genReportReferenceToNullPointer(
304  const ExplodedNode *ErrorNode, const Expr *ArgE) const {
305  if (!BTNullRefArg)
306  BTNullRefArg.reset(new BuiltinBug(this, "Dereference of null pointer"));
307 
308  auto R = std::make_unique<PathSensitiveBugReport>(
309  *BTNullRefArg, "Forming reference to null pointer", ErrorNode);
310  if (ArgE) {
311  const Expr *ArgEDeref = bugreporter::getDerefExpr(ArgE);
312  if (!ArgEDeref)
313  ArgEDeref = ArgE;
314  bugreporter::trackExpressionValue(ErrorNode, ArgEDeref, *R);
315  }
316  return R;
317 
318 }
319 
320 void ento::registerNonNullParamChecker(CheckerManager &mgr) {
321  mgr.registerChecker<NonNullParamChecker>();
322 }
323 
324 bool ento::shouldRegisterNonNullParamChecker(const CheckerManager &mgr) {
325  return true;
326 }
A (possibly-)qualified type.
Definition: Type.h:655
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:89
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
const RecordType * getAsUnionType() const
NOTE: getAs*ArrayType are methods on ASTContext.
Definition: Type.cpp:662
const T * getAs() const
Member-template getAs<specific type>&#39;.
Definition: Type.h:7153
Represents a parameter to a function.
Definition: Decl.h:1595
LineState State
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
Values of this type can never be null.
bool hasAttr() const
Definition: DeclBase.h:547
A single parameter index whose accessors require each use to make explicit the parameter index encodi...
Definition: Attr.h:213
This represents one expression.
Definition: Expr.h:110
#define V(N, I)
Definition: ASTContext.h:2899
QualType getType() const
Definition: Expr.h:142
RecordDecl * getDecl() const
Definition: Type.h:4627
Dataflow Directional Tag Classes.
const Decl * getDecl() const
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
Definition: Type.h:4617
Indicates that the tracking object is a descendant of a referenced-counted OSObject, used in the Darwin kernel.
llvm::iterator_range< specific_attr_iterator< T > > specific_attrs() const
Definition: DeclBase.h:529
The parameter type of a method or function.