Coverage Report

Created: 2023-09-21 18:56

/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
116k
                                          llvm::SmallBitVector &AttrNonNull) {
52
116k
  const Decl *FD = Call.getDecl();
53
54
116k
  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
116k
}
NonNullParamChecker.cpp:void (anonymous namespace)::setBitsAccordingToFunctionAttributes<clang::ento::CallEvent>(clang::ento::CallEvent const&, llvm::SmallBitVector&)
Line
Count
Source
51
102k
                                          llvm::SmallBitVector &AttrNonNull) {
52
102k
  const Decl *FD = Call.getDecl();
53
54
102k
  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
102k
}
NonNullParamChecker.cpp:void (anonymous namespace)::setBitsAccordingToFunctionAttributes<clang::AnyCall>(clang::AnyCall const&, llvm::SmallBitVector&)
Line
Count
Source
51
14.0k
                                          llvm::SmallBitVector &AttrNonNull) {
52
14.0k
  const Decl *FD = Call.getDecl();
53
54
14.0k
  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
14.0k
}
72
73
template <class CallType>
74
void setBitsAccordingToParameterAttributes(const CallType &Call,
75
116k
                                           llvm::SmallBitVector &AttrNonNull) {
76
116k
  for (const ParmVarDecl *Parameter : Call.parameters()) {
77
97.4k
    unsigned ParameterIndex = Parameter->getFunctionScopeIndex();
78
97.4k
    if (ParameterIndex == AttrNonNull.size())
79
0
      break;
80
81
97.4k
    if (Parameter->hasAttr<NonNullAttr>())
82
1
      AttrNonNull.set(ParameterIndex);
83
97.4k
  }
84
116k
}
NonNullParamChecker.cpp:void (anonymous namespace)::setBitsAccordingToParameterAttributes<clang::ento::CallEvent>(clang::ento::CallEvent const&, llvm::SmallBitVector&)
Line
Count
Source
75
102k
                                           llvm::SmallBitVector &AttrNonNull) {
76
102k
  for (const ParmVarDecl *Parameter : Call.parameters()) {
77
89.2k
    unsigned ParameterIndex = Parameter->getFunctionScopeIndex();
78
89.2k
    if (ParameterIndex == AttrNonNull.size())
79
0
      break;
80
81
89.2k
    if (Parameter->hasAttr<NonNullAttr>())
82
1
      AttrNonNull.set(ParameterIndex);
83
89.2k
  }
84
102k
}
NonNullParamChecker.cpp:void (anonymous namespace)::setBitsAccordingToParameterAttributes<clang::AnyCall>(clang::AnyCall const&, llvm::SmallBitVector&)
Line
Count
Source
75
14.0k
                                           llvm::SmallBitVector &AttrNonNull) {
76
14.0k
  for (const ParmVarDecl *Parameter : Call.parameters()) {
77
8.16k
    unsigned ParameterIndex = Parameter->getFunctionScopeIndex();
78
8.16k
    if (ParameterIndex == AttrNonNull.size())
79
0
      break;
80
81
8.16k
    if (Parameter->hasAttr<NonNullAttr>())
82
0
      AttrNonNull.set(ParameterIndex);
83
8.16k
  }
84
14.0k
}
85
86
template <class CallType>
87
llvm::SmallBitVector getNonNullAttrsImpl(const CallType &Call,
88
116k
                                         unsigned ExpectedSize) {
89
116k
  llvm::SmallBitVector AttrNonNull(ExpectedSize);
90
91
116k
  setBitsAccordingToFunctionAttributes(Call, AttrNonNull);
92
116k
  setBitsAccordingToParameterAttributes(Call, AttrNonNull);
93
94
116k
  return AttrNonNull;
95
116k
}
NonNullParamChecker.cpp:llvm::SmallBitVector (anonymous namespace)::getNonNullAttrsImpl<clang::ento::CallEvent>(clang::ento::CallEvent const&, unsigned int)
Line
Count
Source
88
102k
                                         unsigned ExpectedSize) {
89
102k
  llvm::SmallBitVector AttrNonNull(ExpectedSize);
90
91
102k
  setBitsAccordingToFunctionAttributes(Call, AttrNonNull);
92
102k
  setBitsAccordingToParameterAttributes(Call, AttrNonNull);
93
94
102k
  return AttrNonNull;
95
102k
}
NonNullParamChecker.cpp:llvm::SmallBitVector (anonymous namespace)::getNonNullAttrsImpl<clang::AnyCall>(clang::AnyCall const&, unsigned int)
Line
Count
Source
88
14.0k
                                         unsigned ExpectedSize) {
89
14.0k
  llvm::SmallBitVector AttrNonNull(ExpectedSize);
90
91
14.0k
  setBitsAccordingToFunctionAttributes(Call, AttrNonNull);
92
14.0k
  setBitsAccordingToParameterAttributes(Call, AttrNonNull);
93
94
14.0k
  return AttrNonNull;
95
14.0k
}
96
97
/// \return Bitvector marking non-null attributes.
98
102k
llvm::SmallBitVector getNonNullAttrs(const CallEvent &Call) {
99
102k
  return getNonNullAttrsImpl(Call, Call.getNumArgs());
100
102k
}
101
102
/// \return Bitvector marking non-null attributes.
103
14.0k
llvm::SmallBitVector getNonNullAttrs(const AnyCall &Call) {
104
14.0k
  return getNonNullAttrsImpl(Call, Call.param_size());
105
14.0k
}
106
} // end anonymous namespace
107
108
void NonNullParamChecker::checkPreCall(const CallEvent &Call,
109
102k
                                       CheckerContext &C) const {
110
102k
  if (!Call.getDecl())
111
59
    return;
112
113
102k
  llvm::SmallBitVector AttrNonNull = getNonNullAttrs(Call);
114
102k
  unsigned NumArgs = Call.getNumArgs();
115
116
102k
  ProgramStateRef state = C.getState();
117
102k
  ArrayRef<ParmVarDecl *> parms = Call.parameters();
118
119
192k
  for (unsigned idx = 0; idx < NumArgs; 
++idx89.9k
) {
120
    // For vararg functions, a corresponding parameter decl may not exist.
121
89.9k
    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
89.9k
    bool HasRefTypeParam =
126
89.9k
        HasParam ? 
parms[idx]->getType()->isReferenceType()89.2k
:
false694
;
127
89.9k
    bool ExpectedToBeNonNull = AttrNonNull.test(idx);
128
129
89.9k
    if (!ExpectedToBeNonNull && 
!HasRefTypeParam89.8k
)
130
56.3k
      continue;
131
132
    // If the value is unknown or undefined, we can't perform this check.
133
33.6k
    const Expr *ArgE = Call.getArgExpr(idx);
134
33.6k
    SVal V = Call.getArgSVal(idx);
135
33.6k
    auto DV = V.getAs<DefinedSVal>();
136
33.6k
    if (!DV)
137
28
      continue;
138
139
33.5k
    assert(!HasRefTypeParam || isa<Loc>(*DV));
140
141
    // Process the case when the argument is not a location.
142
33.5k
    if (ExpectedToBeNonNull && 
!isa<Loc>(*DV)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 (!isa<Loc>(V))
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.5k
    ConstraintManager &CM = C.getConstraintManager();
174
33.5k
    ProgramStateRef stateNotNull, stateNull;
175
33.5k
    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.5k
    if (stateNull && 
!stateNotNull118
) {
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.5k
    if (stateNull) {
200
69
      if (ExplodedNode *N = C.generateSink(stateNull, C.getPredecessor())) {
201
62
        ImplicitNullDerefEvent event = {
202
62
            V, false, N, &C.getBugReporter(),
203
62
            /*IsDirectDereference=*/HasRefTypeParam};
204
62
        dispatchEvent(event);
205
62
      }
206
69
    }
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.5k
    state = stateNotNull;
211
33.5k
  }
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
102k
  C.addTransition(state);
216
102k
}
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
48.7k
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
48.7k
  if (!Context.inTopFrame())
238
34.4k
    return;
239
240
14.3k
  const LocationContext *LocContext = Context.getLocationContext();
241
242
14.3k
  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
14.3k
  auto AbstractCall = AnyCall::forDecl(FD);
246
14.3k
  if (!AbstractCall)
247
229
    return;
248
249
14.0k
  ProgramStateRef State = Context.getState();
250
14.0k
  llvm::SmallBitVector ParameterNonNullMarks = getNonNullAttrs(*AbstractCall);
251
252
14.0k
  for (const ParmVarDecl *Parameter : AbstractCall->parameters()) {
253
    // 1. Check parameter if it is annotated as non-null
254
8.16k
    if (!ParameterNonNullMarks.test(Parameter->getFunctionScopeIndex()))
255
8.15k
      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
14.0k
  Context.addTransition(State);
275
14.0k
}
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 BugType(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.27k
void ento::registerNonNullParamChecker(CheckerManager &mgr) {
321
1.27k
  mgr.registerChecker<NonNullParamChecker>();
322
1.27k
}
323
324
2.55k
bool ento::shouldRegisterNonNullParamChecker(const CheckerManager &mgr) {
325
2.55k
  return true;
326
2.55k
}