Coverage Report

Created: 2017-10-03 07:32

/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/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
//                     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"
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
26
using namespace clang;
27
using namespace ento;
28
29
namespace {
30
class NonNullParamChecker
31
  : public Checker< check::PreCall, EventDispatcher<ImplicitNullDerefEvent> > {
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
47.5k
                                       CheckerContext &C) const {
49
47.5k
  const Decl *FD = Call.getDecl();
50
47.5k
  if (!FD)
51
36
    return;
52
47.5k
53
47.5k
  // Merge all non-null attributes
54
47.5k
  unsigned NumArgs = Call.getNumArgs();
55
47.5k
  llvm::SmallBitVector AttrNonNull(NumArgs);
56
83
  for (const auto *NonNull : FD->specific_attrs<NonNullAttr>()) {
57
83
    if (
!NonNull->args_size()83
) {
58
39
      AttrNonNull.set(0, NumArgs);
59
39
      break;
60
39
    }
61
44
    
for (unsigned Val : NonNull->args()) 44
{
62
50
      if (Val >= NumArgs)
63
0
        continue;
64
50
      AttrNonNull.set(Val);
65
50
    }
66
83
  }
67
47.5k
68
47.5k
  ProgramStateRef state = C.getState();
69
47.5k
70
47.5k
  CallEvent::param_type_iterator TyI = Call.param_type_begin(),
71
47.5k
                                 TyE = Call.param_type_end();
72
47.5k
73
92.3k
  for (unsigned idx = 0; 
idx < NumArgs92.3k
;
++idx44.8k
) {
74
44.8k
75
44.8k
    // Check if the parameter is a reference. We want to report when reference
76
44.8k
    // to a null pointer is passed as a parameter.
77
44.8k
    bool haveRefTypeParam = false;
78
44.8k
    if (
TyI != TyE44.8k
) {
79
44.4k
      haveRefTypeParam = (*TyI)->isReferenceType();
80
44.4k
      TyI++;
81
44.4k
    }
82
44.8k
83
44.8k
    bool haveAttrNonNull = AttrNonNull[idx];
84
44.8k
    if (
!haveAttrNonNull44.8k
) {
85
44.7k
      // Check if the parameter is also marked 'nonnull'.
86
44.7k
      ArrayRef<ParmVarDecl*> parms = Call.parameters();
87
44.7k
      if (idx < parms.size())
88
44.3k
        haveAttrNonNull = parms[idx]->hasAttr<NonNullAttr>();
89
44.7k
    }
90
44.8k
91
44.8k
    if (
!haveRefTypeParam && 44.8k
!haveAttrNonNull28.6k
)
92
28.5k
      continue;
93
16.2k
94
16.2k
    // If the value is unknown or undefined, we can't perform this check.
95
16.2k
    const Expr *ArgE = Call.getArgExpr(idx);
96
16.2k
    SVal V = Call.getArgSVal(idx);
97
16.2k
    Optional<DefinedSVal> DV = V.getAs<DefinedSVal>();
98
16.2k
    if (!DV)
99
3
      continue;
100
16.2k
101
16.2k
    // Process the case when the argument is not a location.
102
16.2k
    assert(!haveRefTypeParam || DV->getAs<Loc>());
103
16.2k
104
16.2k
    if (
haveAttrNonNull && 16.2k
!DV->getAs<Loc>()97
) {
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 || 23
!UT->getDecl()->hasAttr<TransparentUnionAttr>()9
)
113
14
        continue;
114
9
115
9
      
if (Optional<nonloc::CompoundVal> 9
CSV9
=
116
8
              DV->getAs<nonloc::CompoundVal>()) {
117
8
        nonloc::CompoundVal::iterator CSV_I = CSV->begin();
118
8
        assert(CSV_I != CSV->end());
119
8
        V = *CSV_I;
120
8
        DV = V.getAs<DefinedSVal>();
121
8
        assert(++CSV_I == CSV->end());
122
8
        // FIXME: Handle (some_union){ some_other_union_val }, which turns into
123
8
        // a LazyCompoundVal inside a CompoundVal.
124
8
        if (!V.getAs<Loc>())
125
1
          continue;
126
7
        // Retrieve the corresponding expression.
127
7
        
if (const CompoundLiteralExpr *7
CE7
= dyn_cast<CompoundLiteralExpr>(ArgE))
128
7
          
if (const InitListExpr *7
IE7
=
129
7
                dyn_cast<InitListExpr>(CE->getInitializer()))
130
7
             ArgE = dyn_cast<Expr>(*(IE->begin()));
131
8
132
9
      } else {
133
1
        // FIXME: Handle LazyCompoundVals?
134
1
        continue;
135
1
      }
136
16.2k
    }
137
16.2k
138
16.2k
    ConstraintManager &CM = C.getConstraintManager();
139
16.2k
    ProgramStateRef stateNotNull, stateNull;
140
16.2k
    std::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
141
16.2k
142
16.2k
    if (
stateNull16.2k
) {
143
7.69k
      if (
!stateNotNull7.69k
) {
144
39
        // Generate an error node.  Check for a null node in case
145
39
        // we cache out.
146
39
        if (ExplodedNode *
errorNode39
= C.generateErrorNode(stateNull)) {
147
39
148
39
          std::unique_ptr<BugReport> R;
149
39
          if (haveAttrNonNull)
150
32
            R = genReportNullAttrNonNull(errorNode, ArgE);
151
7
          else 
if (7
haveRefTypeParam7
)
152
7
            R = genReportReferenceToNullPointer(errorNode, ArgE);
153
39
154
39
          // Highlight the range of the argument that was null.
155
39
          R->addRange(Call.getArgSourceRange(idx));
156
39
157
39
          // Emit the bug report.
158
39
          C.emitReport(std::move(R));
159
39
        }
160
39
161
39
        // Always return.  Either we cached out or we just emitted an error.
162
39
        return;
163
39
      }
164
7.66k
      
if (ExplodedNode *7.66k
N7.66k
= C.generateSink(stateNull, C.getPredecessor())) {
165
7.66k
        ImplicitNullDerefEvent event = {
166
7.66k
            V, false, N, &C.getBugReporter(),
167
7.66k
            /*IsDirectDereference=*/haveRefTypeParam};
168
7.66k
        dispatchEvent(event);
169
7.66k
      }
170
7.69k
    }
171
16.2k
172
16.2k
    // If a pointer value passed the check we should assume that it is
173
16.2k
    // indeed not null from this point forward.
174
16.2k
    assert(stateNotNull);
175
16.2k
    state = stateNotNull;
176
16.2k
  }
177
47.5k
178
47.5k
  // If we reach here all of the arguments passed the nonnull check.
179
47.5k
  // If 'state' has been updated generated a new node.
180
47.5k
  C.addTransition(state);
181
47.5k
}
182
183
std::unique_ptr<BugReport>
184
NonNullParamChecker::genReportNullAttrNonNull(const ExplodedNode *ErrorNode,
185
32
                                              const Expr *ArgE) const {
186
32
  // Lazily allocate the BugType object if it hasn't already been
187
32
  // created. Ownership is transferred to the BugReporter object once
188
32
  // the BugReport is passed to 'EmitWarning'.
189
32
  if (!BTAttrNonNull)
190
9
    BTAttrNonNull.reset(new BugType(
191
9
        this, "Argument with 'nonnull' attribute passed null", "API"));
192
32
193
32
  auto R = llvm::make_unique<BugReport>(
194
32
      *BTAttrNonNull,
195
32
      "Null pointer passed as an argument to a 'nonnull' parameter", ErrorNode);
196
32
  if (ArgE)
197
32
    bugreporter::trackNullOrUndefValue(ErrorNode, ArgE, *R);
198
32
199
32
  return R;
200
32
}
201
202
std::unique_ptr<BugReport> NonNullParamChecker::genReportReferenceToNullPointer(
203
7
    const ExplodedNode *ErrorNode, const Expr *ArgE) const {
204
7
  if (!BTNullRefArg)
205
3
    BTNullRefArg.reset(new BuiltinBug(this, "Dereference of null pointer"));
206
7
207
7
  auto R = llvm::make_unique<BugReport>(
208
7
      *BTNullRefArg, "Forming reference to null pointer", ErrorNode);
209
7
  if (
ArgE7
) {
210
7
    const Expr *ArgEDeref = bugreporter::getDerefExpr(ArgE);
211
7
    if (!ArgEDeref)
212
0
      ArgEDeref = ArgE;
213
7
    bugreporter::trackNullOrUndefValue(ErrorNode,
214
7
                                       ArgEDeref,
215
7
                                       *R);
216
7
  }
217
7
  return R;
218
7
219
7
}
220
221
417
void ento::registerNonNullParamChecker(CheckerManager &mgr) {
222
417
  mgr.registerChecker<NonNullParamChecker>();
223
417
}