Coverage Report

Created: 2022-01-18 06:27

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
Line
Count
Source (jump to first uncovered line)
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"
19
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
20
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
21
#include "clang/StaticAnalyzer/Core/Checker.h"
22
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
23
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
24
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.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
111k
                                          llvm::SmallBitVector &AttrNonNull) {
52
111k
  const Decl *FD = Call.getDecl();
53
54
111k
  for (const auto *NonNull : FD->specific_attrs<NonNullAttr>()) {
55
113
    if (!NonNull->args_size()) {
56
      // Lack of attribute parameters means that all of the parameters are
57
      // implicitly marked as non-null.
58
59
      AttrNonNull.set();
59
59
      break;
60
59
    }
61
62
61
    
for (const ParamIdx &Idx : NonNull->args())54
{
63
      // 'nonnull' attribute's parameters are 1-based and should be adjusted to
64
      // match actual AST parameter/argument indices.
65
61
      unsigned IdxAST = Idx.getASTIndex();
66
61
      if (IdxAST >= AttrNonNull.size())
67
0
        continue;
68
61
      AttrNonNull.set(IdxAST);
69
61
    }
70
54
  }
71
111k
}
NonNullParamChecker.cpp:void (anonymous namespace)::setBitsAccordingToFunctionAttributes<clang::ento::CallEvent>(clang::ento::CallEvent const&, llvm::SmallBitVector&)
Line
Count
Source
51
98.2k
                                          llvm::SmallBitVector &AttrNonNull) {
52
98.2k
  const Decl *FD = Call.getDecl();
53
54
98.2k
  for (const auto *NonNull : FD->specific_attrs<NonNullAttr>()) {
55
106
    if (!NonNull->args_size()) {
56
      // Lack of attribute parameters means that all of the parameters are
57
      // implicitly marked as non-null.
58
54
      AttrNonNull.set();
59
54
      break;
60
54
    }
61
62
59
    
for (const ParamIdx &Idx : NonNull->args())52
{
63
      // 'nonnull' attribute's parameters are 1-based and should be adjusted to
64
      // match actual AST parameter/argument indices.
65
59
      unsigned IdxAST = Idx.getASTIndex();
66
59
      if (IdxAST >= AttrNonNull.size())
67
0
        continue;
68
59
      AttrNonNull.set(IdxAST);
69
59
    }
70
52
  }
71
98.2k
}
NonNullParamChecker.cpp:void (anonymous namespace)::setBitsAccordingToFunctionAttributes<clang::AnyCall>(clang::AnyCall const&, llvm::SmallBitVector&)
Line
Count
Source
51
13.1k
                                          llvm::SmallBitVector &AttrNonNull) {
52
13.1k
  const Decl *FD = Call.getDecl();
53
54
13.1k
  for (const auto *NonNull : FD->specific_attrs<NonNullAttr>()) {
55
7
    if (!NonNull->args_size()) {
56
      // Lack of attribute parameters means that all of the parameters are
57
      // implicitly marked as non-null.
58
5
      AttrNonNull.set();
59
5
      break;
60
5
    }
61
62
2
    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
2
      unsigned IdxAST = Idx.getASTIndex();
66
2
      if (IdxAST >= AttrNonNull.size())
67
0
        continue;
68
2
      AttrNonNull.set(IdxAST);
69
2
    }
70
2
  }
71
13.1k
}
72
73
template <class CallType>
74
void setBitsAccordingToParameterAttributes(const CallType &Call,
75
111k
                                           llvm::SmallBitVector &AttrNonNull) {
76
111k
  for (const ParmVarDecl *Parameter : Call.parameters()) {
77
92.9k
    unsigned ParameterIndex = Parameter->getFunctionScopeIndex();
78
92.9k
    if (ParameterIndex == AttrNonNull.size())
79
0
      break;
80
81
92.9k
    if (Parameter->hasAttr<NonNullAttr>())
82
1
      AttrNonNull.set(ParameterIndex);
83
92.9k
  }
84
111k
}
NonNullParamChecker.cpp:void (anonymous namespace)::setBitsAccordingToParameterAttributes<clang::ento::CallEvent>(clang::ento::CallEvent const&, llvm::SmallBitVector&)
Line
Count
Source
75
98.2k
                                           llvm::SmallBitVector &AttrNonNull) {
76
98.2k
  for (const ParmVarDecl *Parameter : Call.parameters()) {
77
85.2k
    unsigned ParameterIndex = Parameter->getFunctionScopeIndex();
78
85.2k
    if (ParameterIndex == AttrNonNull.size())
79
0
      break;
80
81
85.2k
    if (Parameter->hasAttr<NonNullAttr>())
82
1
      AttrNonNull.set(ParameterIndex);
83
85.2k
  }
84
98.2k
}
NonNullParamChecker.cpp:void (anonymous namespace)::setBitsAccordingToParameterAttributes<clang::AnyCall>(clang::AnyCall const&, llvm::SmallBitVector&)
Line
Count
Source
75
13.1k
                                           llvm::SmallBitVector &AttrNonNull) {
76
13.1k
  for (const ParmVarDecl *Parameter : Call.parameters()) {
77
7.73k
    unsigned ParameterIndex = Parameter->getFunctionScopeIndex();
78
7.73k
    if (ParameterIndex == AttrNonNull.size())
79
0
      break;
80
81
7.73k
    if (Parameter->hasAttr<NonNullAttr>())
82
0
      AttrNonNull.set(ParameterIndex);
83
7.73k
  }
84
13.1k
}
85
86
template <class CallType>
87
llvm::SmallBitVector getNonNullAttrsImpl(const CallType &Call,
88
111k
                                         unsigned ExpectedSize) {
89
111k
  llvm::SmallBitVector AttrNonNull(ExpectedSize);
90
91
111k
  setBitsAccordingToFunctionAttributes(Call, AttrNonNull);
92
111k
  setBitsAccordingToParameterAttributes(Call, AttrNonNull);
93
94
111k
  return AttrNonNull;
95
111k
}
NonNullParamChecker.cpp:llvm::SmallBitVector (anonymous namespace)::getNonNullAttrsImpl<clang::ento::CallEvent>(clang::ento::CallEvent const&, unsigned int)
Line
Count
Source
88
98.2k
                                         unsigned ExpectedSize) {
89
98.2k
  llvm::SmallBitVector AttrNonNull(ExpectedSize);
90
91
98.2k
  setBitsAccordingToFunctionAttributes(Call, AttrNonNull);
92
98.2k
  setBitsAccordingToParameterAttributes(Call, AttrNonNull);
93
94
98.2k
  return AttrNonNull;
95
98.2k
}
NonNullParamChecker.cpp:llvm::SmallBitVector (anonymous namespace)::getNonNullAttrsImpl<clang::AnyCall>(clang::AnyCall const&, unsigned int)
Line
Count
Source
88
13.1k
                                         unsigned ExpectedSize) {
89
13.1k
  llvm::SmallBitVector AttrNonNull(ExpectedSize);
90
91
13.1k
  setBitsAccordingToFunctionAttributes(Call, AttrNonNull);
92
13.1k
  setBitsAccordingToParameterAttributes(Call, AttrNonNull);
93
94
13.1k
  return AttrNonNull;
95
13.1k
}
96
97
/// \return Bitvector marking non-null attributes.
98
98.2k
llvm::SmallBitVector getNonNullAttrs(const CallEvent &Call) {
99
98.2k
  return getNonNullAttrsImpl(Call, Call.getNumArgs());
100
98.2k
}
101
102
/// \return Bitvector marking non-null attributes.
103
13.1k
llvm::SmallBitVector getNonNullAttrs(const AnyCall &Call) {
104
13.1k
  return getNonNullAttrsImpl(Call, Call.param_size());
105
13.1k
}
106
} // end anonymous namespace
107
108
void NonNullParamChecker::checkPreCall(const CallEvent &Call,
109
98.2k
                                       CheckerContext &C) const {
110
98.2k
  if (!Call.getDecl())
111
56
    return;
112
113
98.2k
  llvm::SmallBitVector AttrNonNull = getNonNullAttrs(Call);
114
98.2k
  unsigned NumArgs = Call.getNumArgs();
115
116
98.2k
  ProgramStateRef state = C.getState();
117
98.2k
  ArrayRef<ParmVarDecl *> parms = Call.parameters();
118
119
183k
  for (unsigned idx = 0; idx < NumArgs; 
++idx85.6k
) {
120
    // For vararg functions, a corresponding parameter decl may not exist.
121
85.6k
    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
85.6k
    bool HasRefTypeParam =
126
85.6k
        HasParam ? 
parms[idx]->getType()->isReferenceType()85.1k
:
false485
;
127
85.6k
    bool ExpectedToBeNonNull = AttrNonNull.test(idx);
128
129
85.6k
    if (!ExpectedToBeNonNull && 
!HasRefTypeParam85.5k
)
130
51.6k
      continue;
131
132
    // If the value is unknown or undefined, we can't perform this check.
133
33.9k
    const Expr *ArgE = Call.getArgExpr(idx);
134
33.9k
    SVal V = Call.getArgSVal(idx);
135
33.9k
    auto DV = V.getAs<DefinedSVal>();
136
33.9k
    if (!DV)
137
72
      continue;
138
139
33.9k
    assert(!HasRefTypeParam || DV->getAs<Loc>());
140
141
    // Process the case when the argument is not a location.
142
33.9k
    if (ExpectedToBeNonNull && 
!DV->getAs<Loc>()133
) {
143
      // If the argument is a union type, we want to handle a potential
144
      // transparent_union GCC extension.
145
24
      if (!ArgE)
146
0
        continue;
147
148
24
      QualType T = ArgE->getType();
149
24
      const RecordType *UT = T->getAsUnionType();
150
24
      if (!UT || 
!UT->getDecl()->hasAttr<TransparentUnionAttr>()9
)
151
15
        continue;
152
153
9
      auto CSV = DV->getAs<nonloc::CompoundVal>();
154
155
      // FIXME: Handle LazyCompoundVals?
156
9
      if (!CSV)
157
1
        continue;
158
159
8
      V = *(CSV->begin());
160
8
      DV = V.getAs<DefinedSVal>();
161
8
      assert(++CSV->begin() == CSV->end());
162
      // FIXME: Handle (some_union){ some_other_union_val }, which turns into
163
      // a LazyCompoundVal inside a CompoundVal.
164
8
      if (!V.getAs<Loc>())
165
1
        continue;
166
167
      // Retrieve the corresponding expression.
168
7
      if (const auto *CE = dyn_cast<CompoundLiteralExpr>(ArgE))
169
7
        if (const auto *IE = dyn_cast<InitListExpr>(CE->getInitializer()))
170
7
          ArgE = dyn_cast<Expr>(*(IE->begin()));
171
7
    }
172
173
33.8k
    ConstraintManager &CM = C.getConstraintManager();
174
33.8k
    ProgramStateRef stateNotNull, stateNull;
175
33.8k
    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
33.8k
    if (stateNull && 
!stateNotNull105
) {
180
49
      if (ExplodedNode *errorNode = C.generateErrorNode(stateNull)) {
181
182
49
        std::unique_ptr<BugReport> R;
183
49
        if (ExpectedToBeNonNull)
184
39
          R = genReportNullAttrNonNull(errorNode, ArgE, idx + 1);
185
10
        else if (HasRefTypeParam)
186
10
          R = genReportReferenceToNullPointer(errorNode, ArgE);
187
188
        // Highlight the range of the argument that was null.
189
49
        R->addRange(Call.getArgSourceRange(idx));
190
191
        // Emit the bug report.
192
49
        C.emitReport(std::move(R));
193
49
      }
194
195
      // Always return.  Either we cached out or we just emitted an error.
196
49
      return;
197
49
    }
198
199
33.8k
    if (stateNull) {
200
56
      if (ExplodedNode *N = C.generateSink(stateNull, C.getPredecessor())) {
201
49
        ImplicitNullDerefEvent event = {
202
49
            V, false, N, &C.getBugReporter(),
203
49
            /*IsDirectDereference=*/HasRefTypeParam};
204
49
        dispatchEvent(event);
205
49
      }
206
56
    }
207
208
    // If a pointer value passed the check we should assume that it is
209
    // indeed not null from this point forward.
210
33.8k
    state = stateNotNull;
211
33.8k
  }
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
98.1k
  C.addTransition(state);
216
98.1k
}
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
47.8k
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
47.8k
  if (!Context.inTopFrame())
238
34.3k
    return;
239
240
13.4k
  const LocationContext *LocContext = Context.getLocationContext();
241
242
13.4k
  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
13.4k
  auto AbstractCall = AnyCall::forDecl(FD);
246
13.4k
  if (!AbstractCall)
247
227
    return;
248
249
13.1k
  ProgramStateRef State = Context.getState();
250
13.1k
  llvm::SmallBitVector ParameterNonNullMarks = getNonNullAttrs(*AbstractCall);
251
252
13.1k
  for (const ParmVarDecl *Parameter : AbstractCall->parameters()) {
253
    // 1. Check parameter if it is annotated as non-null
254
7.73k
    if (!ParameterNonNullMarks.test(Parameter->getFunctionScopeIndex()))
255
7.72k
      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
8
    if (!Parameter->getType()->isPointerType())
261
1
      continue;
262
263
7
    Loc ParameterLoc = State->getLValue(Parameter, LocContext);
264
    // We never consider top-level function parameters undefined.
265
7
    auto StoredVal =
266
7
        State->getSVal(ParameterLoc).castAs<DefinedOrUnknownSVal>();
267
268
    // 3. Assume that it is indeed non-null
269
7
    if (ProgramStateRef NewState = State->assume(StoredVal, true)) {
270
7
      State = NewState;
271
7
    }
272
7
  }
273
274
13.1k
  Context.addTransition(State);
275
13.1k
}
276
277
std::unique_ptr<PathSensitiveBugReport>
278
NonNullParamChecker::genReportNullAttrNonNull(const ExplodedNode *ErrorNode,
279
                                              const Expr *ArgE,
280
39
                                              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
39
  if (!BTAttrNonNull)
285
13
    BTAttrNonNull.reset(new BugType(
286
13
        this, "Argument with 'nonnull' attribute passed null", "API"));
287
288
39
  llvm::SmallString<256> SBuf;
289
39
  llvm::raw_svector_ostream OS(SBuf);
290
39
  OS << "Null pointer passed to "
291
39
     << IdxOfArg << llvm::getOrdinalSuffix(IdxOfArg)
292
39
     << " parameter expecting 'nonnull'";
293
294
39
  auto R =
295
39
      std::make_unique<PathSensitiveBugReport>(*BTAttrNonNull, SBuf, ErrorNode);
296
39
  if (ArgE)
297
39
    bugreporter::trackExpressionValue(ErrorNode, ArgE, *R);
298
299
39
  return R;
300
39
}
301
302
std::unique_ptr<PathSensitiveBugReport>
303
NonNullParamChecker::genReportReferenceToNullPointer(
304
10
    const ExplodedNode *ErrorNode, const Expr *ArgE) const {
305
10
  if (!BTNullRefArg)
306
6
    BTNullRefArg.reset(new BuiltinBug(this, "Dereference of null pointer"));
307
308
10
  auto R = std::make_unique<PathSensitiveBugReport>(
309
10
      *BTNullRefArg, "Forming reference to null pointer", ErrorNode);
310
10
  if (ArgE) {
311
10
    const Expr *ArgEDeref = bugreporter::getDerefExpr(ArgE);
312
10
    if (!ArgEDeref)
313
0
      ArgEDeref = ArgE;
314
10
    bugreporter::trackExpressionValue(ErrorNode, ArgEDeref, *R);
315
10
  }
316
10
  return R;
317
318
10
}
319
320
1.15k
void ento::registerNonNullParamChecker(CheckerManager &mgr) {
321
1.15k
  mgr.registerChecker<NonNullParamChecker>();
322
1.15k
}
323
324
2.31k
bool ento::shouldRegisterNonNullParamChecker(const CheckerManager &mgr) {
325
2.31k
  return true;
326
2.31k
}