Coverage Report

Created: 2023-09-12 09:32

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- CallAndMessageChecker.cpp ------------------------------*- 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 CallAndMessageChecker, a builtin checker that checks for various
10
// errors of call and objc message expressions.
11
//
12
//===----------------------------------------------------------------------===//
13
14
#include "clang/AST/ExprCXX.h"
15
#include "clang/AST/ParentMap.h"
16
#include "clang/Basic/TargetInfo.h"
17
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
18
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
19
#include "clang/StaticAnalyzer/Core/Checker.h"
20
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
21
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
22
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
23
#include "llvm/ADT/SmallString.h"
24
#include "llvm/ADT/StringExtras.h"
25
#include "llvm/Support/Casting.h"
26
#include "llvm/Support/raw_ostream.h"
27
28
using namespace clang;
29
using namespace ento;
30
31
namespace {
32
33
class CallAndMessageChecker
34
    : public Checker<check::PreObjCMessage, check::ObjCMessageNil,
35
                     check::PreCall> {
36
  mutable std::unique_ptr<BugType> BT_call_null;
37
  mutable std::unique_ptr<BugType> BT_call_undef;
38
  mutable std::unique_ptr<BugType> BT_cxx_call_null;
39
  mutable std::unique_ptr<BugType> BT_cxx_call_undef;
40
  mutable std::unique_ptr<BugType> BT_call_arg;
41
  mutable std::unique_ptr<BugType> BT_cxx_delete_undef;
42
  mutable std::unique_ptr<BugType> BT_msg_undef;
43
  mutable std::unique_ptr<BugType> BT_objc_prop_undef;
44
  mutable std::unique_ptr<BugType> BT_objc_subscript_undef;
45
  mutable std::unique_ptr<BugType> BT_msg_arg;
46
  mutable std::unique_ptr<BugType> BT_msg_ret;
47
  mutable std::unique_ptr<BugType> BT_call_few_args;
48
49
public:
50
  // These correspond with the checker options. Looking at other checkers such
51
  // as MallocChecker and CStringChecker, this is similar as to how they pull
52
  // off having a modeling class, but emitting diagnostics under a smaller
53
  // checker's name that can be safely disabled without disturbing the
54
  // underlaying modeling engine.
55
  // The reason behind having *checker options* rather then actual *checkers*
56
  // here is that CallAndMessage is among the oldest checkers out there, and can
57
  // be responsible for the majority of the reports on any given project. This
58
  // is obviously not ideal, but changing checker name has the consequence of
59
  // changing the issue hashes associated with the reports, and databases
60
  // relying on this (CodeChecker, for instance) would suffer greatly.
61
  // If we ever end up making changes to the issue hash generation algorithm, or
62
  // the warning messages here, we should totally jump on the opportunity to
63
  // convert these to actual checkers.
64
  enum CheckKind {
65
    CK_FunctionPointer,
66
    CK_ParameterCount,
67
    CK_CXXThisMethodCall,
68
    CK_CXXDeallocationArg,
69
    CK_ArgInitializedness,
70
    CK_ArgPointeeInitializedness,
71
    CK_NilReceiver,
72
    CK_UndefReceiver,
73
    CK_NumCheckKinds
74
  };
75
76
  bool ChecksEnabled[CK_NumCheckKinds] = {false};
77
  // The original core.CallAndMessage checker name. This should rather be an
78
  // array, as seen in MallocChecker and CStringChecker.
79
  CheckerNameRef OriginalName;
80
81
  void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
82
83
  /// Fill in the return value that results from messaging nil based on the
84
  /// return type and architecture and diagnose if the return value will be
85
  /// garbage.
86
  void checkObjCMessageNil(const ObjCMethodCall &msg, CheckerContext &C) const;
87
88
  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
89
90
  ProgramStateRef checkFunctionPointerCall(const CallExpr *CE,
91
                                           CheckerContext &C,
92
                                           ProgramStateRef State) const;
93
94
  ProgramStateRef checkCXXMethodCall(const CXXInstanceCall *CC,
95
                                     CheckerContext &C,
96
                                     ProgramStateRef State) const;
97
98
  ProgramStateRef checkParameterCount(const CallEvent &Call, CheckerContext &C,
99
                                      ProgramStateRef State) const;
100
101
  ProgramStateRef checkCXXDeallocation(const CXXDeallocatorCall *DC,
102
                                       CheckerContext &C,
103
                                       ProgramStateRef State) const;
104
105
  ProgramStateRef checkArgInitializedness(const CallEvent &Call,
106
                                          CheckerContext &C,
107
                                          ProgramStateRef State) const;
108
109
private:
110
  bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange ArgRange,
111
                          const Expr *ArgEx, int ArgumentNumber,
112
                          bool CheckUninitFields, const CallEvent &Call,
113
                          std::unique_ptr<BugType> &BT,
114
                          const ParmVarDecl *ParamDecl) const;
115
116
  static void emitBadCall(BugType *BT, CheckerContext &C, const Expr *BadE);
117
  void emitNilReceiverBug(CheckerContext &C, const ObjCMethodCall &msg,
118
                          ExplodedNode *N) const;
119
120
  void HandleNilReceiver(CheckerContext &C,
121
                         ProgramStateRef state,
122
                         const ObjCMethodCall &msg) const;
123
124
103
  void LazyInit_BT(const char *desc, std::unique_ptr<BugType> &BT) const {
125
103
    if (!BT)
126
61
      BT.reset(new BugType(OriginalName, desc));
127
103
  }
128
  bool uninitRefOrPointer(CheckerContext &C, const SVal &V,
129
                          SourceRange ArgRange, const Expr *ArgEx,
130
                          std::unique_ptr<BugType> &BT,
131
                          const ParmVarDecl *ParamDecl, const char *BD,
132
                          int ArgumentNumber) const;
133
};
134
} // end anonymous namespace
135
136
void CallAndMessageChecker::emitBadCall(BugType *BT, CheckerContext &C,
137
85
                                        const Expr *BadE) {
138
85
  ExplodedNode *N = C.generateErrorNode();
139
85
  if (!N)
140
0
    return;
141
142
85
  auto R = std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
143
85
  if (BadE) {
144
85
    R->addRange(BadE->getSourceRange());
145
85
    if (BadE->isGLValue())
146
11
      BadE = bugreporter::getDerefExpr(BadE);
147
85
    bugreporter::trackExpressionValue(N, BadE, *R);
148
85
  }
149
85
  C.emitReport(std::move(R));
150
85
}
151
152
static void describeUninitializedArgumentInCall(const CallEvent &Call,
153
                                                int ArgumentNumber,
154
63
                                                llvm::raw_svector_ostream &Os) {
155
63
  switch (Call.getKind()) {
156
9
  case CE_ObjCMessage: {
157
9
    const ObjCMethodCall &Msg = cast<ObjCMethodCall>(Call);
158
9
    switch (Msg.getMessageKind()) {
159
2
    case OCM_Message:
160
2
      Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
161
2
         << " argument in message expression is an uninitialized value";
162
2
      return;
163
1
    case OCM_PropertyAccess:
164
1
      assert(Msg.isSetter() && "Getters have no args");
165
1
      Os << "Argument for property setter is an uninitialized value";
166
1
      return;
167
6
    case OCM_Subscript:
168
6
      if (Msg.isSetter() && 
(ArgumentNumber == 0)4
)
169
2
        Os << "Argument for subscript setter is an uninitialized value";
170
4
      else
171
4
        Os << "Subscript index is an uninitialized value";
172
6
      return;
173
9
    }
174
0
    llvm_unreachable("Unknown message kind.");
175
0
  }
176
2
  case CE_Block:
177
2
    Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
178
2
       << " block call argument is an uninitialized value";
179
2
    return;
180
52
  default:
181
52
    Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
182
52
       << " function call argument is an uninitialized value";
183
52
    return;
184
63
  }
185
63
}
186
187
bool CallAndMessageChecker::uninitRefOrPointer(
188
    CheckerContext &C, const SVal &V, SourceRange ArgRange, const Expr *ArgEx,
189
    std::unique_ptr<BugType> &BT, const ParmVarDecl *ParamDecl, const char *BD,
190
90.0k
    int ArgumentNumber) const {
191
192
  // The pointee being uninitialized is a sign of code smell, not a bug, no need
193
  // to sink here.
194
90.0k
  if (!ChecksEnabled[CK_ArgPointeeInitializedness])
195
89.9k
    return false;
196
197
  // No parameter declaration available, i.e. variadic function argument.
198
77
  if(!ParamDecl)
199
4
    return false;
200
201
  // If parameter is declared as pointer to const in function declaration,
202
  // then check if corresponding argument in function call is
203
  // pointing to undefined symbol value (uninitialized memory).
204
73
  SmallString<200> Buf;
205
73
  llvm::raw_svector_ostream Os(Buf);
206
207
73
  if (ParamDecl->getType()->isPointerType()) {
208
47
    Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
209
47
       << " function call argument is a pointer to uninitialized value";
210
47
  } else 
if (26
ParamDecl->getType()->isReferenceType()26
) {
211
13
    Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
212
13
       << " function call argument is an uninitialized value";
213
13
  } else
214
13
    return false;
215
216
60
  if(!ParamDecl->getType()->getPointeeType().isConstQualified())
217
14
    return false;
218
219
46
  if (const MemRegion *SValMemRegion = V.getAsRegion()) {
220
46
    const ProgramStateRef State = C.getState();
221
46
    const SVal PSV = State->getSVal(SValMemRegion, C.getASTContext().CharTy);
222
46
    if (PSV.isUndef()) {
223
26
      if (ExplodedNode *N = C.generateErrorNode()) {
224
26
        LazyInit_BT(BD, BT);
225
26
        auto R = std::make_unique<PathSensitiveBugReport>(*BT, Os.str(), N);
226
26
        R->addRange(ArgRange);
227
26
        if (ArgEx)
228
26
          bugreporter::trackExpressionValue(N, ArgEx, *R);
229
230
26
        C.emitReport(std::move(R));
231
26
      }
232
26
      return true;
233
26
    }
234
46
  }
235
20
  return false;
236
46
}
237
238
namespace {
239
class FindUninitializedField {
240
public:
241
  SmallVector<const FieldDecl *, 10> FieldChain;
242
243
private:
244
  StoreManager &StoreMgr;
245
  MemRegionManager &MrMgr;
246
  Store store;
247
248
public:
249
  FindUninitializedField(StoreManager &storeMgr, MemRegionManager &mrMgr,
250
                         Store s)
251
9.81k
      : StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}
252
253
9.82k
  bool Find(const TypedValueRegion *R) {
254
9.82k
    QualType T = R->getValueType();
255
9.82k
    if (const RecordType *RT = T->getAsStructureType()) {
256
9.78k
      const RecordDecl *RD = RT->getDecl()->getDefinition();
257
9.78k
      assert(RD && "Referred record has no definition");
258
9.82k
      
for (const auto *I : RD->fields())9.78k
{
259
9.82k
        const FieldRegion *FR = MrMgr.getFieldRegion(I, R);
260
9.82k
        FieldChain.push_back(I);
261
9.82k
        T = I->getType();
262
9.82k
        if (T->getAsStructureType()) {
263
14
          if (Find(FR))
264
0
            return true;
265
9.80k
        } else {
266
9.80k
          const SVal &V = StoreMgr.getBinding(store, loc::MemRegionVal(FR));
267
9.80k
          if (V.isUndef())
268
11
            return true;
269
9.80k
        }
270
9.80k
        FieldChain.pop_back();
271
9.80k
      }
272
9.78k
    }
273
274
9.81k
    return false;
275
9.82k
  }
276
};
277
} // namespace
278
279
bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
280
                                               SVal V,
281
                                               SourceRange ArgRange,
282
                                               const Expr *ArgEx,
283
                                               int ArgumentNumber,
284
                                               bool CheckUninitFields,
285
                                               const CallEvent &Call,
286
                                               std::unique_ptr<BugType> &BT,
287
                                               const ParmVarDecl *ParamDecl
288
90.0k
                                               ) const {
289
90.0k
  const char *BD = "Uninitialized argument value";
290
291
90.0k
  if (uninitRefOrPointer(C, V, ArgRange, ArgEx, BT, ParamDecl, BD,
292
90.0k
                         ArgumentNumber))
293
26
    return true;
294
295
90.0k
  if (V.isUndef()) {
296
68
    if (!ChecksEnabled[CK_ArgInitializedness]) {
297
5
      C.addSink();
298
5
      return true;
299
5
    }
300
63
    if (ExplodedNode *N = C.generateErrorNode()) {
301
63
      LazyInit_BT(BD, BT);
302
      // Generate a report for this bug.
303
63
      SmallString<200> Buf;
304
63
      llvm::raw_svector_ostream Os(Buf);
305
63
      describeUninitializedArgumentInCall(Call, ArgumentNumber, Os);
306
63
      auto R = std::make_unique<PathSensitiveBugReport>(*BT, Os.str(), N);
307
308
63
      R->addRange(ArgRange);
309
63
      if (ArgEx)
310
63
        bugreporter::trackExpressionValue(N, ArgEx, *R);
311
63
      C.emitReport(std::move(R));
312
63
    }
313
63
    return true;
314
68
  }
315
316
89.9k
  if (!CheckUninitFields)
317
33.1k
    return false;
318
319
56.7k
  if (auto LV = V.getAs<nonloc::LazyCompoundVal>()) {
320
9.81k
    const LazyCompoundValData *D = LV->getCVData();
321
9.81k
    FindUninitializedField F(C.getState()->getStateManager().getStoreManager(),
322
9.81k
                             C.getSValBuilder().getRegionManager(),
323
9.81k
                             D->getStore());
324
325
9.81k
    if (F.Find(D->getRegion())) {
326
11
      if (!ChecksEnabled[CK_ArgInitializedness]) {
327
4
        C.addSink();
328
4
        return true;
329
4
      }
330
7
      if (ExplodedNode *N = C.generateErrorNode()) {
331
7
        LazyInit_BT(BD, BT);
332
7
        SmallString<512> Str;
333
7
        llvm::raw_svector_ostream os(Str);
334
7
        os << "Passed-by-value struct argument contains uninitialized data";
335
336
7
        if (F.FieldChain.size() == 1)
337
7
          os << " (e.g., field: '" << *F.FieldChain[0] << "')";
338
0
        else {
339
0
          os << " (e.g., via the field chain: '";
340
0
          bool first = true;
341
0
          for (SmallVectorImpl<const FieldDecl *>::iterator
342
0
               DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
343
0
            if (first)
344
0
              first = false;
345
0
            else
346
0
              os << '.';
347
0
            os << **DI;
348
0
          }
349
0
          os << "')";
350
0
        }
351
352
        // Generate a report for this bug.
353
7
        auto R = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
354
7
        R->addRange(ArgRange);
355
356
7
        if (ArgEx)
357
7
          bugreporter::trackExpressionValue(N, ArgEx, *R);
358
        // FIXME: enhance track back for uninitialized value for arbitrary
359
        // memregions
360
7
        C.emitReport(std::move(R));
361
7
      }
362
7
      return true;
363
11
    }
364
9.81k
  }
365
366
56.7k
  return false;
367
56.7k
}
368
369
ProgramStateRef CallAndMessageChecker::checkFunctionPointerCall(
370
72.3k
    const CallExpr *CE, CheckerContext &C, ProgramStateRef State) const {
371
372
72.3k
  const Expr *Callee = CE->getCallee()->IgnoreParens();
373
72.3k
  const LocationContext *LCtx = C.getLocationContext();
374
72.3k
  SVal L = State->getSVal(Callee, LCtx);
375
376
72.3k
  if (L.isUndef()) {
377
8
    if (!ChecksEnabled[CK_FunctionPointer]) {
378
4
      C.addSink(State);
379
4
      return nullptr;
380
4
    }
381
4
    if (!BT_call_undef)
382
4
      BT_call_undef.reset(new BugType(
383
4
          OriginalName,
384
4
          "Called function pointer is an uninitialized pointer value"));
385
4
    emitBadCall(BT_call_undef.get(), C, Callee);
386
4
    return nullptr;
387
8
  }
388
389
72.3k
  ProgramStateRef StNonNull, StNull;
390
72.3k
  std::tie(StNonNull, StNull) = State->assume(L.castAs<DefinedOrUnknownSVal>());
391
392
72.3k
  if (StNull && 
!StNonNull81
) {
393
8
    if (!ChecksEnabled[CK_FunctionPointer]) {
394
4
      C.addSink(StNull);
395
4
      return nullptr;
396
4
    }
397
4
    if (!BT_call_null)
398
3
      BT_call_null.reset(new BugType(
399
3
          OriginalName, "Called function pointer is null (null dereference)"));
400
4
    emitBadCall(BT_call_null.get(), C, Callee);
401
4
    return nullptr;
402
8
  }
403
404
72.3k
  return StNonNull;
405
72.3k
}
406
407
ProgramStateRef CallAndMessageChecker::checkParameterCount(
408
102k
    const CallEvent &Call, CheckerContext &C, ProgramStateRef State) const {
409
410
  // If we have a function or block declaration, we can make sure we pass
411
  // enough parameters.
412
102k
  unsigned Params = Call.parameters().size();
413
102k
  if (Call.getNumArgs() >= Params)
414
102k
    return State;
415
416
11
  if (!ChecksEnabled[CK_ParameterCount]) {
417
4
    C.addSink(State);
418
4
    return nullptr;
419
4
  }
420
421
7
  ExplodedNode *N = C.generateErrorNode();
422
7
  if (!N)
423
0
    return nullptr;
424
425
7
  LazyInit_BT("Function call with too few arguments", BT_call_few_args);
426
427
7
  SmallString<512> Str;
428
7
  llvm::raw_svector_ostream os(Str);
429
7
  if (isa<AnyFunctionCall>(Call)) {
430
5
    os << "Function ";
431
5
  } else {
432
2
    assert(isa<BlockCall>(Call));
433
2
    os << "Block ";
434
2
  }
435
7
  os << "taking " << Params << " argument" << (Params == 1 ? 
""3
:
"s"4
)
436
7
     << " is called with fewer (" << Call.getNumArgs() << ")";
437
438
7
  C.emitReport(
439
7
      std::make_unique<PathSensitiveBugReport>(*BT_call_few_args, os.str(), N));
440
7
  return nullptr;
441
7
}
442
443
ProgramStateRef CallAndMessageChecker::checkCXXMethodCall(
444
13.4k
    const CXXInstanceCall *CC, CheckerContext &C, ProgramStateRef State) const {
445
446
13.4k
  SVal V = CC->getCXXThisVal();
447
13.4k
  if (V.isUndef()) {
448
13
    if (!ChecksEnabled[CK_CXXThisMethodCall]) {
449
4
      C.addSink(State);
450
4
      return nullptr;
451
4
    }
452
9
    if (!BT_cxx_call_undef)
453
9
      BT_cxx_call_undef.reset(new BugType(
454
9
          OriginalName, "Called C++ object pointer is uninitialized"));
455
9
    emitBadCall(BT_cxx_call_undef.get(), C, CC->getCXXThisExpr());
456
9
    return nullptr;
457
13
  }
458
459
13.4k
  ProgramStateRef StNonNull, StNull;
460
13.4k
  std::tie(StNonNull, StNull) = State->assume(V.castAs<DefinedOrUnknownSVal>());
461
462
13.4k
  if (StNull && 
!StNonNull311
) {
463
72
    if (!ChecksEnabled[CK_CXXThisMethodCall]) {
464
4
      C.addSink(StNull);
465
4
      return nullptr;
466
4
    }
467
68
    if (!BT_cxx_call_null)
468
29
      BT_cxx_call_null.reset(
469
29
          new BugType(OriginalName, "Called C++ object pointer is null"));
470
68
    emitBadCall(BT_cxx_call_null.get(), C, CC->getCXXThisExpr());
471
68
    return nullptr;
472
72
  }
473
474
13.4k
  return StNonNull;
475
13.4k
}
476
477
ProgramStateRef
478
CallAndMessageChecker::checkCXXDeallocation(const CXXDeallocatorCall *DC,
479
                                            CheckerContext &C,
480
475
                                            ProgramStateRef State) const {
481
475
  const CXXDeleteExpr *DE = DC->getOriginExpr();
482
475
  assert(DE);
483
475
  SVal Arg = C.getSVal(DE->getArgument());
484
475
  if (!Arg.isUndef())
485
445
    return State;
486
487
30
  if (!ChecksEnabled[CK_CXXDeallocationArg]) {
488
4
    C.addSink(State);
489
4
    return nullptr;
490
4
  }
491
492
26
  StringRef Desc;
493
26
  ExplodedNode *N = C.generateErrorNode();
494
26
  if (!N)
495
0
    return nullptr;
496
26
  if (!BT_cxx_delete_undef)
497
8
    BT_cxx_delete_undef.reset(
498
8
        new BugType(OriginalName, "Uninitialized argument value"));
499
26
  if (DE->isArrayFormAsWritten())
500
12
    Desc = "Argument to 'delete[]' is uninitialized";
501
14
  else
502
14
    Desc = "Argument to 'delete' is uninitialized";
503
26
  auto R =
504
26
      std::make_unique<PathSensitiveBugReport>(*BT_cxx_delete_undef, Desc, N);
505
26
  bugreporter::trackExpressionValue(N, DE, *R);
506
26
  C.emitReport(std::move(R));
507
26
  return nullptr;
508
26
}
509
510
ProgramStateRef CallAndMessageChecker::checkArgInitializedness(
511
102k
    const CallEvent &Call, CheckerContext &C, ProgramStateRef State) const {
512
513
102k
  const Decl *D = Call.getDecl();
514
515
  // Don't check for uninitialized field values in arguments if the
516
  // caller has a body that is available and we have the chance to inline it.
517
  // This is a hack, but is a reasonable compromise betweens sometimes warning
518
  // and sometimes not depending on if we decide to inline a function.
519
102k
  const bool checkUninitFields =
520
102k
      !(C.getAnalysisManager().shouldInlineCall() && 
(102k
D102k
&&
D->getBody()102k
));
521
522
102k
  std::unique_ptr<BugType> *BT;
523
102k
  if (isa<ObjCMethodCall>(Call))
524
3.67k
    BT = &BT_msg_arg;
525
98.9k
  else
526
98.9k
    BT = &BT_call_arg;
527
528
102k
  const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
529
192k
  for (unsigned i = 0, e = Call.getNumArgs(); i != e; 
++i89.9k
) {
530
90.0k
    const ParmVarDecl *ParamDecl = nullptr;
531
90.0k
    if (FD && 
i < FD->getNumParams()88.9k
)
532
88.3k
      ParamDecl = FD->getParamDecl(i);
533
90.0k
    if (PreVisitProcessArg(C, Call.getArgSVal(i), Call.getArgSourceRange(i),
534
90.0k
                           Call.getArgExpr(i), i, checkUninitFields, Call, *BT,
535
90.0k
                           ParamDecl))
536
105
      return nullptr;
537
90.0k
  }
538
102k
  return State;
539
102k
}
540
541
void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
542
102k
                                         CheckerContext &C) const {
543
102k
  ProgramStateRef State = C.getState();
544
545
102k
  if (const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()))
546
72.3k
    State = checkFunctionPointerCall(CE, C, State);
547
548
102k
  if (!State)
549
16
    return;
550
551
102k
  if (Call.getDecl())
552
102k
    State = checkParameterCount(Call, C, State);
553
554
102k
  if (!State)
555
11
    return;
556
557
102k
  if (const auto *CC = dyn_cast<CXXInstanceCall>(&Call))
558
13.4k
    State = checkCXXMethodCall(CC, C, State);
559
560
102k
  if (!State)
561
85
    return;
562
563
102k
  if (const auto *DC = dyn_cast<CXXDeallocatorCall>(&Call))
564
475
    State = checkCXXDeallocation(DC, C, State);
565
566
102k
  if (!State)
567
30
    return;
568
569
102k
  State = checkArgInitializedness(Call, C, State);
570
571
  // If we make it here, record our assumptions about the callee.
572
102k
  C.addTransition(State);
573
102k
}
574
575
void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
576
3.73k
                                                CheckerContext &C) const {
577
3.73k
  SVal recVal = msg.getReceiverSVal();
578
3.73k
  if (recVal.isUndef()) {
579
8
    if (!ChecksEnabled[CK_UndefReceiver]) {
580
0
      C.addSink();
581
0
      return;
582
0
    }
583
8
    if (ExplodedNode *N = C.generateErrorNode()) {
584
8
      BugType *BT = nullptr;
585
8
      switch (msg.getMessageKind()) {
586
2
      case OCM_Message:
587
2
        if (!BT_msg_undef)
588
2
          BT_msg_undef.reset(new BugType(OriginalName,
589
2
                                         "Receiver in message expression "
590
2
                                         "is an uninitialized value"));
591
2
        BT = BT_msg_undef.get();
592
2
        break;
593
2
      case OCM_PropertyAccess:
594
2
        if (!BT_objc_prop_undef)
595
2
          BT_objc_prop_undef.reset(new BugType(
596
2
              OriginalName,
597
2
              "Property access on an uninitialized object pointer"));
598
2
        BT = BT_objc_prop_undef.get();
599
2
        break;
600
4
      case OCM_Subscript:
601
4
        if (!BT_objc_subscript_undef)
602
2
          BT_objc_subscript_undef.reset(new BugType(
603
2
              OriginalName,
604
2
              "Subscript access on an uninitialized object pointer"));
605
4
        BT = BT_objc_subscript_undef.get();
606
4
        break;
607
8
      }
608
8
      assert(BT && "Unknown message kind.");
609
610
8
      auto R = std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
611
8
      const ObjCMessageExpr *ME = msg.getOriginExpr();
612
8
      R->addRange(ME->getReceiverRange());
613
614
      // FIXME: getTrackNullOrUndefValueVisitor can't handle "super" yet.
615
8
      if (const Expr *ReceiverE = ME->getInstanceReceiver())
616
8
        bugreporter::trackExpressionValue(N, ReceiverE, *R);
617
8
      C.emitReport(std::move(R));
618
8
    }
619
8
    return;
620
8
  }
621
3.73k
}
622
623
void CallAndMessageChecker::checkObjCMessageNil(const ObjCMethodCall &msg,
624
96
                                                CheckerContext &C) const {
625
96
  HandleNilReceiver(C, C.getState(), msg);
626
96
}
627
628
void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
629
                                               const ObjCMethodCall &msg,
630
7
                                               ExplodedNode *N) const {
631
7
  if (!ChecksEnabled[CK_NilReceiver]) {
632
0
    C.addSink();
633
0
    return;
634
0
  }
635
636
7
  if (!BT_msg_ret)
637
2
    BT_msg_ret.reset(
638
2
        new BugType(OriginalName, "Receiver in message expression is 'nil'"));
639
640
7
  const ObjCMessageExpr *ME = msg.getOriginExpr();
641
642
7
  QualType ResTy = msg.getResultType();
643
644
7
  SmallString<200> buf;
645
7
  llvm::raw_svector_ostream os(buf);
646
7
  os << "The receiver of message '";
647
7
  ME->getSelector().print(os);
648
7
  os << "' is nil";
649
7
  if (ResTy->isReferenceType()) {
650
2
    os << ", which results in forming a null reference";
651
5
  } else {
652
5
    os << " and returns a value of type '";
653
5
    msg.getResultType().print(os, C.getLangOpts());
654
5
    os << "' that will be garbage";
655
5
  }
656
657
7
  auto report =
658
7
      std::make_unique<PathSensitiveBugReport>(*BT_msg_ret, os.str(), N);
659
7
  report->addRange(ME->getReceiverRange());
660
  // FIXME: This won't track "self" in messages to super.
661
7
  if (const Expr *receiver = ME->getInstanceReceiver()) {
662
7
    bugreporter::trackExpressionValue(N, receiver, *report);
663
7
  }
664
7
  C.emitReport(std::move(report));
665
7
}
666
667
15
static bool supportsNilWithFloatRet(const llvm::Triple &triple) {
668
15
  return (triple.getVendor() == llvm::Triple::Apple &&
669
15
          (triple.isiOS() || 
triple.isWatchOS()10
||
670
15
           
!triple.isMacOSXVersionLT(10,5)10
));
671
15
}
672
673
void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
674
                                              ProgramStateRef state,
675
96
                                              const ObjCMethodCall &Msg) const {
676
96
  ASTContext &Ctx = C.getASTContext();
677
96
  static CheckerProgramPointTag Tag(this, "NilReceiver");
678
679
  // Check the return type of the message expression.  A message to nil will
680
  // return different values depending on the return type and the architecture.
681
96
  QualType RetTy = Msg.getResultType();
682
96
  CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
683
96
  const LocationContext *LCtx = C.getLocationContext();
684
685
96
  if (CanRetTy->isStructureOrClassType()) {
686
    // Structure returns are safe since the compiler zeroes them out.
687
4
    SVal V = C.getSValBuilder().makeZeroVal(RetTy);
688
4
    C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
689
4
    return;
690
4
  }
691
692
  // Other cases: check if sizeof(return type) > sizeof(void*)
693
92
  if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap()
694
79
                                  .isConsumedExpr(Msg.getOriginExpr())) {
695
    // Compute: sizeof(void *) and sizeof(return type)
696
74
    const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
697
74
    const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
698
699
74
    if (CanRetTy.getTypePtr()->isReferenceType()||
700
74
        
(72
voidPtrSize < returnTypeSize72
&&
701
72
         
!(15
supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple())15
&&
702
15
           
(10
Ctx.FloatTy == CanRetTy10
||
703
10
            Ctx.DoubleTy == CanRetTy ||
704
10
            
Ctx.LongDoubleTy == CanRetTy8
||
705
10
            
Ctx.LongLongTy == CanRetTy6
||
706
10
            
Ctx.UnsignedLongLongTy == CanRetTy2
)))) {
707
7
      if (ExplodedNode *N = C.generateErrorNode(state, &Tag))
708
7
        emitNilReceiverBug(C, Msg, N);
709
7
      return;
710
7
    }
711
712
    // Handle the safe cases where the return value is 0 if the
713
    // receiver is nil.
714
    //
715
    // FIXME: For now take the conservative approach that we only
716
    // return null values if we *know* that the receiver is nil.
717
    // This is because we can have surprises like:
718
    //
719
    //   ... = [[NSScreens screens] objectAtIndex:0];
720
    //
721
    // What can happen is that [... screens] could return nil, but
722
    // it most likely isn't nil.  We should assume the semantics
723
    // of this case unless we have *a lot* more knowledge.
724
    //
725
67
    SVal V = C.getSValBuilder().makeZeroVal(RetTy);
726
67
    C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
727
67
    return;
728
74
  }
729
730
18
  C.addTransition(state);
731
18
}
732
733
1.27k
void ento::registerCallAndMessageModeling(CheckerManager &mgr) {
734
1.27k
  mgr.registerChecker<CallAndMessageChecker>();
735
1.27k
}
736
737
5.10k
bool ento::shouldRegisterCallAndMessageModeling(const CheckerManager &mgr) {
738
5.10k
  return true;
739
5.10k
}
740
741
1.27k
void ento::registerCallAndMessageChecker(CheckerManager &mgr) {
742
1.27k
  CallAndMessageChecker *checker = mgr.getChecker<CallAndMessageChecker>();
743
744
1.27k
  checker->OriginalName = mgr.getCurrentCheckerName();
745
746
1.27k
#define QUERY_CHECKER_OPTION(OPTION)                                           \
747
10.1k
  checker->ChecksEnabled[CallAndMessageChecker::CK_##OPTION] =                 \
748
10.1k
      mgr.getAnalyzerOptions().getCheckerBooleanOption(                        \
749
10.1k
          mgr.getCurrentCheckerName(), #OPTION);
750
751
1.27k
  QUERY_CHECKER_OPTION(FunctionPointer)
752
1.27k
  QUERY_CHECKER_OPTION(ParameterCount)
753
1.27k
  QUERY_CHECKER_OPTION(CXXThisMethodCall)
754
1.27k
  QUERY_CHECKER_OPTION(CXXDeallocationArg)
755
1.27k
  QUERY_CHECKER_OPTION(ArgInitializedness)
756
1.27k
  QUERY_CHECKER_OPTION(ArgPointeeInitializedness)
757
1.27k
  QUERY_CHECKER_OPTION(NilReceiver)
758
1.27k
  QUERY_CHECKER_OPTION(UndefReceiver)
759
1.27k
}
760
761
2.55k
bool ento::shouldRegisterCallAndMessageChecker(const CheckerManager &mgr) {
762
2.55k
  return true;
763
2.55k
}