Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/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/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
18
#include "clang/AST/Attr.h"
19
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
20
#include "clang/StaticAnalyzer/Core/Checker.h"
21
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
22
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
23
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
24
25
using namespace clang;
26
using namespace ento;
27
28
namespace {
29
class NonNullParamChecker
30
  : public Checker< check::PreCall, EventDispatcher<ImplicitNullDerefEvent> > {
31
  mutable std::unique_ptr<BugType> BTAttrNonNull;
32
  mutable std::unique_ptr<BugType> BTNullRefArg;
33
34
public:
35
36
  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
37
38
  std::unique_ptr<BugReport>
39
  genReportNullAttrNonNull(const ExplodedNode *ErrorN, const Expr *ArgE) const;
40
  std::unique_ptr<BugReport>
41
  genReportReferenceToNullPointer(const ExplodedNode *ErrorN,
42
                                  const Expr *ArgE) const;
43
};
44
} // end anonymous namespace
45
46
/// \return Bitvector marking non-null attributes.
47
75.6k
static llvm::SmallBitVector getNonNullAttrs(const CallEvent &Call) {
48
75.6k
  const Decl *FD = Call.getDecl();
49
75.6k
  unsigned NumArgs = Call.getNumArgs();
50
75.6k
  llvm::SmallBitVector AttrNonNull(NumArgs);
51
75.6k
  for (const auto *NonNull : FD->specific_attrs<NonNullAttr>()) {
52
98
    if (!NonNull->args_size()) {
53
51
      AttrNonNull.set(0, NumArgs);
54
51
      break;
55
51
    }
56
53
    
for (const ParamIdx &Idx : NonNull->args())47
{
57
53
      unsigned IdxAST = Idx.getASTIndex();
58
53
      if (IdxAST >= NumArgs)
59
0
        continue;
60
53
      AttrNonNull.set(IdxAST);
61
53
    }
62
47
  }
63
75.6k
  return AttrNonNull;
64
75.6k
}
65
66
void NonNullParamChecker::checkPreCall(const CallEvent &Call,
67
75.6k
                                       CheckerContext &C) const {
68
75.6k
  if (!Call.getDecl())
69
49
    return;
70
75.6k
71
75.6k
  llvm::SmallBitVector AttrNonNull = getNonNullAttrs(Call);
72
75.6k
  unsigned NumArgs = Call.getNumArgs();
73
75.6k
74
75.6k
  ProgramStateRef state = C.getState();
75
75.6k
  ArrayRef<ParmVarDecl*> parms = Call.parameters();
76
75.6k
77
139k
  for (unsigned idx = 0; idx < NumArgs; 
++idx64.2k
) {
78
64.2k
    // For vararg functions, a corresponding parameter decl may not exist.
79
64.2k
    bool HasParam = idx < parms.size();
80
64.2k
81
64.2k
    // Check if the parameter is a reference. We want to report when reference
82
64.2k
    // to a null pointer is passed as a parameter.
83
64.2k
    bool haveRefTypeParam =
84
64.2k
        HasParam ? 
parms[idx]->getType()->isReferenceType()63.8k
:
false450
;
85
64.2k
    bool haveAttrNonNull = AttrNonNull[idx];
86
64.2k
87
64.2k
    // Check if the parameter is also marked 'nonnull'.
88
64.2k
    if (!haveAttrNonNull && 
HasParam64.1k
)
89
63.6k
      haveAttrNonNull = parms[idx]->hasAttr<NonNullAttr>();
90
64.2k
91
64.2k
    if (!haveAttrNonNull && 
!haveRefTypeParam64.1k
)
92
38.1k
      continue;
93
26.1k
94
26.1k
    // If the value is unknown or undefined, we can't perform this check.
95
26.1k
    const Expr *ArgE = Call.getArgExpr(idx);
96
26.1k
    SVal V = Call.getArgSVal(idx);
97
26.1k
    auto DV = V.getAs<DefinedSVal>();
98
26.1k
    if (!DV)
99
63
      continue;
100
26.0k
101
26.0k
    assert(!haveRefTypeParam || DV->getAs<Loc>());
102
26.0k
103
26.0k
    // Process the case when the argument is not a location.
104
26.0k
    if (haveAttrNonNull && 
!DV->getAs<Loc>()124
) {
105
23
      // If the argument is a union type, we want to handle a potential
106
23
      // transparent_union GCC extension.
107
23
      if (!ArgE)
108
0
        continue;
109
23
110
23
      QualType T = ArgE->getType();
111
23
      const RecordType *UT = T->getAsUnionType();
112
23
      if (!UT || 
!UT->getDecl()->hasAttr<TransparentUnionAttr>()9
)
113
14
        continue;
114
9
115
9
      auto CSV = DV->getAs<nonloc::CompoundVal>();
116
9
117
9
      // FIXME: Handle LazyCompoundVals?
118
9
      if (!CSV)
119
1
        continue;
120
8
121
8
      V = *(CSV->begin());
122
8
      DV = V.getAs<DefinedSVal>();
123
8
      assert(++CSV->begin() == CSV->end());
124
8
      // FIXME: Handle (some_union){ some_other_union_val }, which turns into
125
8
      // a LazyCompoundVal inside a CompoundVal.
126
8
      if (!V.getAs<Loc>())
127
1
        continue;
128
7
129
7
      // Retrieve the corresponding expression.
130
7
      if (const auto *CE = dyn_cast<CompoundLiteralExpr>(ArgE))
131
7
        if (const auto *IE = dyn_cast<InitListExpr>(CE->getInitializer()))
132
7
          ArgE = dyn_cast<Expr>(*(IE->begin()));
133
7
    }
134
26.0k
135
26.0k
    ConstraintManager &CM = C.getConstraintManager();
136
26.0k
    ProgramStateRef stateNotNull, stateNull;
137
26.0k
    std::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
138
26.0k
139
26.0k
    // Generate an error node.  Check for a null node in case
140
26.0k
    // we cache out.
141
26.0k
    if (stateNull && 
!stateNotNull97
) {
142
42
      if (ExplodedNode *errorNode = C.generateErrorNode(stateNull)) {
143
42
144
42
        std::unique_ptr<BugReport> R;
145
42
        if (haveAttrNonNull)
146
32
          R = genReportNullAttrNonNull(errorNode, ArgE);
147
10
        else if (haveRefTypeParam)
148
10
          R = genReportReferenceToNullPointer(errorNode, ArgE);
149
42
150
42
        // Highlight the range of the argument that was null.
151
42
        R->addRange(Call.getArgSourceRange(idx));
152
42
153
42
        // Emit the bug report.
154
42
        C.emitReport(std::move(R));
155
42
      }
156
42
157
42
      // Always return.  Either we cached out or we just emitted an error.
158
42
      return;
159
42
    }
160
25.9k
161
25.9k
    if (stateNull) {
162
55
      if (ExplodedNode *N = C.generateSink(stateNull, C.getPredecessor())) {
163
48
        ImplicitNullDerefEvent event = {
164
48
          V, false, N, &C.getBugReporter(),
165
48
          /*IsDirectDereference=*/haveRefTypeParam};
166
48
        dispatchEvent(event);
167
48
      }
168
55
    }
169
25.9k
170
25.9k
    // If a pointer value passed the check we should assume that it is
171
25.9k
    // indeed not null from this point forward.
172
25.9k
    state = stateNotNull;
173
25.9k
  }
174
75.6k
175
75.6k
  // If we reach here all of the arguments passed the nonnull check.
176
75.6k
  // If 'state' has been updated generated a new node.
177
75.6k
  C.addTransition(state);
178
75.5k
}
179
180
std::unique_ptr<BugReport>
181
NonNullParamChecker::genReportNullAttrNonNull(const ExplodedNode *ErrorNode,
182
32
                                              const Expr *ArgE) const {
183
32
  // Lazily allocate the BugType object if it hasn't already been
184
32
  // created. Ownership is transferred to the BugReporter object once
185
32
  // the BugReport is passed to 'EmitWarning'.
186
32
  if (!BTAttrNonNull)
187
9
    BTAttrNonNull.reset(new BugType(
188
9
        this, "Argument with 'nonnull' attribute passed null", "API"));
189
32
190
32
  auto R = llvm::make_unique<BugReport>(
191
32
      *BTAttrNonNull,
192
32
      "Null pointer passed as an argument to a 'nonnull' parameter", ErrorNode);
193
32
  if (ArgE)
194
32
    bugreporter::trackExpressionValue(ErrorNode, ArgE, *R);
195
32
196
32
  return R;
197
32
}
198
199
std::unique_ptr<BugReport> NonNullParamChecker::genReportReferenceToNullPointer(
200
10
    const ExplodedNode *ErrorNode, const Expr *ArgE) const {
201
10
  if (!BTNullRefArg)
202
6
    BTNullRefArg.reset(new BuiltinBug(this, "Dereference of null pointer"));
203
10
204
10
  auto R = llvm::make_unique<BugReport>(
205
10
      *BTNullRefArg, "Forming reference to null pointer", ErrorNode);
206
10
  if (ArgE) {
207
10
    const Expr *ArgEDeref = bugreporter::getDerefExpr(ArgE);
208
10
    if (!ArgEDeref)
209
0
      ArgEDeref = ArgE;
210
10
    bugreporter::trackExpressionValue(ErrorNode, ArgEDeref, *R);
211
10
  }
212
10
  return R;
213
10
214
10
}
215
216
675
void ento::registerNonNullParamChecker(CheckerManager &mgr) {
217
675
  mgr.registerChecker<NonNullParamChecker>();
218
675
}
219
220
676
bool ento::shouldRegisterNonNullParamChecker(const LangOptions &LO) {
221
676
  return true;
222
676
}