Coverage Report

Created: 2022-01-18 06:27

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
Line
Count
Source (jump to first uncovered line)
1
//== BasicObjCFoundationChecks.cpp - Simple Apple-Foundation checks -*- 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 file defines BasicObjCFoundationChecks, a class that encapsulates
10
//  a set of simple checks to run on Objective-C code using Apple's Foundation
11
//  classes.
12
//
13
//===----------------------------------------------------------------------===//
14
15
#include "clang/AST/ASTContext.h"
16
#include "clang/AST/DeclObjC.h"
17
#include "clang/AST/Expr.h"
18
#include "clang/AST/ExprObjC.h"
19
#include "clang/AST/StmtObjC.h"
20
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
21
#include "clang/Analysis/SelectorExtras.h"
22
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
23
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
24
#include "clang/StaticAnalyzer/Core/Checker.h"
25
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
26
#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
27
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
28
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
29
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
30
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
31
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
32
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
33
#include "llvm/ADT/SmallString.h"
34
#include "llvm/ADT/StringMap.h"
35
#include "llvm/Support/raw_ostream.h"
36
37
using namespace clang;
38
using namespace ento;
39
using namespace llvm;
40
41
namespace {
42
class APIMisuse : public BugType {
43
public:
44
  APIMisuse(const CheckerBase *checker, const char *name)
45
83
      : BugType(checker, name, "API Misuse (Apple)") {}
46
};
47
} // end anonymous namespace
48
49
//===----------------------------------------------------------------------===//
50
// Utility functions.
51
//===----------------------------------------------------------------------===//
52
53
46
static StringRef GetReceiverInterfaceName(const ObjCMethodCall &msg) {
54
46
  if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
55
46
    return ID->getIdentifier()->getName();
56
0
  return StringRef();
57
46
}
58
59
enum FoundationClass {
60
  FC_None,
61
  FC_NSArray,
62
  FC_NSDictionary,
63
  FC_NSEnumerator,
64
  FC_NSNull,
65
  FC_NSOrderedSet,
66
  FC_NSSet,
67
  FC_NSString
68
};
69
70
static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID,
71
1.48k
                                      bool IncludeSuperclasses = true) {
72
1.48k
  static llvm::StringMap<FoundationClass> Classes;
73
1.48k
  if (Classes.empty()) {
74
15
    Classes["NSArray"] = FC_NSArray;
75
15
    Classes["NSDictionary"] = FC_NSDictionary;
76
15
    Classes["NSEnumerator"] = FC_NSEnumerator;
77
15
    Classes["NSNull"] = FC_NSNull;
78
15
    Classes["NSOrderedSet"] = FC_NSOrderedSet;
79
15
    Classes["NSSet"] = FC_NSSet;
80
15
    Classes["NSString"] = FC_NSString;
81
15
  }
82
83
  // FIXME: Should we cache this at all?
84
1.48k
  FoundationClass result = Classes.lookup(ID->getIdentifier()->getName());
85
1.48k
  if (result == FC_None && 
IncludeSuperclasses784
)
86
688
    if (const ObjCInterfaceDecl *Super = ID->getSuperClass())
87
441
      return findKnownClass(Super);
88
89
1.04k
  return result;
90
1.48k
}
91
92
//===----------------------------------------------------------------------===//
93
// NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
94
//===----------------------------------------------------------------------===//
95
96
namespace {
97
  class NilArgChecker : public Checker<check::PreObjCMessage,
98
                                       check::PostStmt<ObjCDictionaryLiteral>,
99
                                       check::PostStmt<ObjCArrayLiteral> > {
100
    mutable std::unique_ptr<APIMisuse> BT;
101
102
    mutable llvm::SmallDenseMap<Selector, unsigned, 16> StringSelectors;
103
    mutable Selector ArrayWithObjectSel;
104
    mutable Selector AddObjectSel;
105
    mutable Selector InsertObjectAtIndexSel;
106
    mutable Selector ReplaceObjectAtIndexWithObjectSel;
107
    mutable Selector SetObjectAtIndexedSubscriptSel;
108
    mutable Selector ArrayByAddingObjectSel;
109
    mutable Selector DictionaryWithObjectForKeySel;
110
    mutable Selector SetObjectForKeySel;
111
    mutable Selector SetObjectForKeyedSubscriptSel;
112
    mutable Selector RemoveObjectForKeySel;
113
114
    void warnIfNilExpr(const Expr *E,
115
                       const char *Msg,
116
                       CheckerContext &C) const;
117
118
    void warnIfNilArg(CheckerContext &C,
119
                      const ObjCMethodCall &msg, unsigned Arg,
120
                      FoundationClass Class,
121
                      bool CanBeSubscript = false) const;
122
123
    void generateBugReport(ExplodedNode *N,
124
                           StringRef Msg,
125
                           SourceRange Range,
126
                           const Expr *Expr,
127
                           CheckerContext &C) const;
128
129
  public:
130
    void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
131
    void checkPostStmt(const ObjCDictionaryLiteral *DL,
132
                       CheckerContext &C) const;
133
    void checkPostStmt(const ObjCArrayLiteral *AL,
134
                       CheckerContext &C) const;
135
  };
136
} // end anonymous namespace
137
138
void NilArgChecker::warnIfNilExpr(const Expr *E,
139
                                  const char *Msg,
140
46
                                  CheckerContext &C) const {
141
46
  ProgramStateRef State = C.getState();
142
46
  if (State->isNull(C.getSVal(E)).isConstrainedTrue()) {
143
144
9
    if (ExplodedNode *N = C.generateErrorNode()) {
145
8
      generateBugReport(N, Msg, E->getSourceRange(), E, C);
146
8
    }
147
9
  }
148
46
}
149
150
void NilArgChecker::warnIfNilArg(CheckerContext &C,
151
                                 const ObjCMethodCall &msg,
152
                                 unsigned int Arg,
153
                                 FoundationClass Class,
154
65
                                 bool CanBeSubscript) const {
155
  // Check if the argument is nil.
156
65
  ProgramStateRef State = C.getState();
157
65
  if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue())
158
20
      return;
159
160
  // NOTE: We cannot throw non-fatal errors from warnIfNilExpr,
161
  // because it's called multiple times from some callers, so it'd cause
162
  // an unwanted state split if two or more non-fatal errors are thrown
163
  // within the same checker callback. For now we don't want to, but
164
  // it'll need to be fixed if we ever want to.
165
45
  if (ExplodedNode *N = C.generateErrorNode()) {
166
44
    SmallString<128> sbuf;
167
44
    llvm::raw_svector_ostream os(sbuf);
168
169
44
    if (CanBeSubscript && 
msg.getMessageKind() == OCM_Subscript5
) {
170
171
4
      if (Class == FC_NSArray) {
172
1
        os << "Array element cannot be nil";
173
3
      } else if (Class == FC_NSDictionary) {
174
3
        if (Arg == 0) {
175
0
          os << "Value stored into '";
176
0
          os << GetReceiverInterfaceName(msg) << "' cannot be nil";
177
3
        } else {
178
3
          assert(Arg == 1);
179
0
          os << "'"<< GetReceiverInterfaceName(msg) << "' key cannot be nil";
180
3
        }
181
3
      } else
182
0
        llvm_unreachable("Missing foundation class for the subscript expr");
183
184
40
    } else {
185
40
      if (Class == FC_NSDictionary) {
186
7
        if (Arg == 0)
187
3
          os << "Value argument ";
188
4
        else {
189
4
          assert(Arg == 1);
190
0
          os << "Key argument ";
191
4
        }
192
0
        os << "to '";
193
7
        msg.getSelector().print(os);
194
7
        os << "' cannot be nil";
195
33
      } else {
196
33
        os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '";
197
33
        msg.getSelector().print(os);
198
33
        os << "' cannot be nil";
199
33
      }
200
40
    }
201
202
0
    generateBugReport(N, os.str(), msg.getArgSourceRange(Arg),
203
44
                      msg.getArgExpr(Arg), C);
204
44
  }
205
45
}
206
207
void NilArgChecker::generateBugReport(ExplodedNode *N,
208
                                      StringRef Msg,
209
                                      SourceRange Range,
210
                                      const Expr *E,
211
52
                                      CheckerContext &C) const {
212
52
  if (!BT)
213
8
    BT.reset(new APIMisuse(this, "nil argument"));
214
215
52
  auto R = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
216
52
  R->addRange(Range);
217
52
  bugreporter::trackExpressionValue(N, E, *R);
218
52
  C.emitReport(std::move(R));
219
52
}
220
221
void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
222
491
                                        CheckerContext &C) const {
223
491
  const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
224
491
  if (!ID)
225
8
    return;
226
227
483
  FoundationClass Class = findKnownClass(ID);
228
229
483
  static const unsigned InvalidArgIndex = UINT_MAX;
230
483
  unsigned Arg = InvalidArgIndex;
231
483
  bool CanBeSubscript = false;
232
233
483
  if (Class == FC_NSString) {
234
329
    Selector S = msg.getSelector();
235
236
329
    if (S.isUnarySelector())
237
293
      return;
238
239
36
    if (StringSelectors.empty()) {
240
4
      ASTContext &Ctx = C.getASTContext();
241
4
      Selector Sels[] = {
242
4
          getKeywordSelector(Ctx, "caseInsensitiveCompare"),
243
4
          getKeywordSelector(Ctx, "compare"),
244
4
          getKeywordSelector(Ctx, "compare", "options"),
245
4
          getKeywordSelector(Ctx, "compare", "options", "range"),
246
4
          getKeywordSelector(Ctx, "compare", "options", "range", "locale"),
247
4
          getKeywordSelector(Ctx, "componentsSeparatedByCharactersInSet"),
248
4
          getKeywordSelector(Ctx, "initWithFormat"),
249
4
          getKeywordSelector(Ctx, "localizedCaseInsensitiveCompare"),
250
4
          getKeywordSelector(Ctx, "localizedCompare"),
251
4
          getKeywordSelector(Ctx, "localizedStandardCompare"),
252
4
      };
253
4
      for (Selector KnownSel : Sels)
254
40
        StringSelectors[KnownSel] = 0;
255
4
    }
256
36
    auto I = StringSelectors.find(S);
257
36
    if (I == StringSelectors.end())
258
8
      return;
259
28
    Arg = I->second;
260
154
  } else if (Class == FC_NSArray) {
261
33
    Selector S = msg.getSelector();
262
263
33
    if (S.isUnarySelector())
264
17
      return;
265
266
16
    if (ArrayWithObjectSel.isNull()) {
267
5
      ASTContext &Ctx = C.getASTContext();
268
5
      ArrayWithObjectSel = getKeywordSelector(Ctx, "arrayWithObject");
269
5
      AddObjectSel = getKeywordSelector(Ctx, "addObject");
270
5
      InsertObjectAtIndexSel =
271
5
          getKeywordSelector(Ctx, "insertObject", "atIndex");
272
5
      ReplaceObjectAtIndexWithObjectSel =
273
5
          getKeywordSelector(Ctx, "replaceObjectAtIndex", "withObject");
274
5
      SetObjectAtIndexedSubscriptSel =
275
5
          getKeywordSelector(Ctx, "setObject", "atIndexedSubscript");
276
5
      ArrayByAddingObjectSel = getKeywordSelector(Ctx, "arrayByAddingObject");
277
5
    }
278
279
16
    if (S == ArrayWithObjectSel || S == AddObjectSel ||
280
16
        
S == InsertObjectAtIndexSel10
||
S == ArrayByAddingObjectSel9
) {
281
8
      Arg = 0;
282
8
    } else if (S == SetObjectAtIndexedSubscriptSel) {
283
2
      Arg = 0;
284
2
      CanBeSubscript = true;
285
6
    } else if (S == ReplaceObjectAtIndexWithObjectSel) {
286
1
      Arg = 1;
287
1
    }
288
121
  } else if (Class == FC_NSDictionary) {
289
21
    Selector S = msg.getSelector();
290
291
21
    if (S.isUnarySelector())
292
1
      return;
293
294
20
    if (DictionaryWithObjectForKeySel.isNull()) {
295
2
      ASTContext &Ctx = C.getASTContext();
296
2
      DictionaryWithObjectForKeySel =
297
2
          getKeywordSelector(Ctx, "dictionaryWithObject", "forKey");
298
2
      SetObjectForKeySel = getKeywordSelector(Ctx, "setObject", "forKey");
299
2
      SetObjectForKeyedSubscriptSel =
300
2
          getKeywordSelector(Ctx, "setObject", "forKeyedSubscript");
301
2
      RemoveObjectForKeySel = getKeywordSelector(Ctx, "removeObjectForKey");
302
2
    }
303
304
20
    if (S == DictionaryWithObjectForKeySel || 
S == SetObjectForKeySel18
) {
305
7
      Arg = 0;
306
7
      warnIfNilArg(C, msg, /* Arg */1, Class);
307
13
    } else if (S == SetObjectForKeyedSubscriptSel) {
308
8
      CanBeSubscript = true;
309
8
      Arg = 1;
310
8
    } else 
if (5
S == RemoveObjectForKeySel5
) {
311
4
      Arg = 0;
312
4
    }
313
20
  }
314
315
  // If argument is '0', report a warning.
316
164
  if ((Arg != InvalidArgIndex))
317
58
    warnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
318
164
}
319
320
void NilArgChecker::checkPostStmt(const ObjCArrayLiteral *AL,
321
7
                                  CheckerContext &C) const {
322
7
  unsigned NumOfElements = AL->getNumElements();
323
25
  for (unsigned i = 0; i < NumOfElements; 
++i18
) {
324
18
    warnIfNilExpr(AL->getElement(i), "Array element cannot be nil", C);
325
18
  }
326
7
}
327
328
void NilArgChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
329
9
                                  CheckerContext &C) const {
330
9
  unsigned NumOfElements = DL->getNumElements();
331
23
  for (unsigned i = 0; i < NumOfElements; 
++i14
) {
332
14
    ObjCDictionaryElement Element = DL->getKeyValueElement(i);
333
14
    warnIfNilExpr(Element.Key, "Dictionary key cannot be nil", C);
334
14
    warnIfNilExpr(Element.Value, "Dictionary value cannot be nil", C);
335
14
  }
336
9
}
337
338
//===----------------------------------------------------------------------===//
339
// Checking for mismatched types passed to CFNumberCreate/CFNumberGetValue.
340
//===----------------------------------------------------------------------===//
341
342
namespace {
343
class CFNumberChecker : public Checker< check::PreStmt<CallExpr> > {
344
  mutable std::unique_ptr<APIMisuse> BT;
345
  mutable IdentifierInfo *ICreate, *IGetValue;
346
public:
347
47
  CFNumberChecker() : ICreate(nullptr), IGetValue(nullptr) {}
348
349
  void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
350
351
private:
352
  void EmitError(const TypedRegion* R, const Expr *Ex,
353
                uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
354
};
355
} // end anonymous namespace
356
357
enum CFNumberType {
358
  kCFNumberSInt8Type = 1,
359
  kCFNumberSInt16Type = 2,
360
  kCFNumberSInt32Type = 3,
361
  kCFNumberSInt64Type = 4,
362
  kCFNumberFloat32Type = 5,
363
  kCFNumberFloat64Type = 6,
364
  kCFNumberCharType = 7,
365
  kCFNumberShortType = 8,
366
  kCFNumberIntType = 9,
367
  kCFNumberLongType = 10,
368
  kCFNumberLongLongType = 11,
369
  kCFNumberFloatType = 12,
370
  kCFNumberDoubleType = 13,
371
  kCFNumberCFIndexType = 14,
372
  kCFNumberNSIntegerType = 15,
373
  kCFNumberCGFloatType = 16
374
};
375
376
8
static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
377
8
  static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
378
379
8
  if (i < kCFNumberCharType)
380
7
    return FixedSize[i-1];
381
382
1
  QualType T;
383
384
1
  switch (i) {
385
0
    case kCFNumberCharType:     T = Ctx.CharTy;     break;
386
0
    case kCFNumberShortType:    T = Ctx.ShortTy;    break;
387
0
    case kCFNumberIntType:      T = Ctx.IntTy;      break;
388
1
    case kCFNumberLongType:     T = Ctx.LongTy;     break;
389
0
    case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
390
0
    case kCFNumberFloatType:    T = Ctx.FloatTy;    break;
391
0
    case kCFNumberDoubleType:   T = Ctx.DoubleTy;   break;
392
0
    case kCFNumberCFIndexType:
393
0
    case kCFNumberNSIntegerType:
394
0
    case kCFNumberCGFloatType:
395
      // FIXME: We need a way to map from names to Type*.
396
0
    default:
397
0
      return None;
398
1
  }
399
400
1
  return Ctx.getTypeSize(T);
401
1
}
402
403
#if 0
404
static const char* GetCFNumberTypeStr(uint64_t i) {
405
  static const char* Names[] = {
406
    "kCFNumberSInt8Type",
407
    "kCFNumberSInt16Type",
408
    "kCFNumberSInt32Type",
409
    "kCFNumberSInt64Type",
410
    "kCFNumberFloat32Type",
411
    "kCFNumberFloat64Type",
412
    "kCFNumberCharType",
413
    "kCFNumberShortType",
414
    "kCFNumberIntType",
415
    "kCFNumberLongType",
416
    "kCFNumberLongLongType",
417
    "kCFNumberFloatType",
418
    "kCFNumberDoubleType",
419
    "kCFNumberCFIndexType",
420
    "kCFNumberNSIntegerType",
421
    "kCFNumberCGFloatType"
422
  };
423
424
  return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
425
}
426
#endif
427
428
void CFNumberChecker::checkPreStmt(const CallExpr *CE,
429
305
                                         CheckerContext &C) const {
430
305
  ProgramStateRef state = C.getState();
431
305
  const FunctionDecl *FD = C.getCalleeDecl(CE);
432
305
  if (!FD)
433
3
    return;
434
435
302
  ASTContext &Ctx = C.getASTContext();
436
302
  if (!ICreate) {
437
19
    ICreate = &Ctx.Idents.get("CFNumberCreate");
438
19
    IGetValue = &Ctx.Idents.get("CFNumberGetValue");
439
19
  }
440
302
  if (!(FD->getIdentifier() == ICreate || 
FD->getIdentifier() == IGetValue296
) ||
441
302
      
CE->getNumArgs() != 38
)
442
294
    return;
443
444
  // Get the value of the "theType" argument.
445
8
  SVal TheTypeVal = C.getSVal(CE->getArg(1));
446
447
  // FIXME: We really should allow ranges of valid theType values, and
448
  //   bifurcate the state appropriately.
449
8
  Optional<nonloc::ConcreteInt> V = TheTypeVal.getAs<nonloc::ConcreteInt>();
450
8
  if (!V)
451
0
    return;
452
453
8
  uint64_t NumberKind = V->getValue().getLimitedValue();
454
8
  Optional<uint64_t> OptCFNumberSize = GetCFNumberSize(Ctx, NumberKind);
455
456
  // FIXME: In some cases we can emit an error.
457
8
  if (!OptCFNumberSize)
458
0
    return;
459
460
8
  uint64_t CFNumberSize = *OptCFNumberSize;
461
462
  // Look at the value of the integer being passed by reference.  Essentially
463
  // we want to catch cases where the value passed in is not equal to the
464
  // size of the type being created.
465
8
  SVal TheValueExpr = C.getSVal(CE->getArg(2));
466
467
  // FIXME: Eventually we should handle arbitrary locations.  We can do this
468
  //  by having an enhanced memory model that does low-level typing.
469
8
  Optional<loc::MemRegionVal> LV = TheValueExpr.getAs<loc::MemRegionVal>();
470
8
  if (!LV)
471
0
    return;
472
473
8
  const TypedValueRegion* R = dyn_cast<TypedValueRegion>(LV->stripCasts());
474
8
  if (!R)
475
0
    return;
476
477
8
  QualType T = Ctx.getCanonicalType(R->getValueType());
478
479
  // FIXME: If the pointee isn't an integer type, should we flag a warning?
480
  //  People can do weird stuff with pointers.
481
482
8
  if (!T->isIntegralOrEnumerationType())
483
0
    return;
484
485
8
  uint64_t PrimitiveTypeSize = Ctx.getTypeSize(T);
486
487
8
  if (PrimitiveTypeSize == CFNumberSize)
488
3
    return;
489
490
  // FIXME: We can actually create an abstract "CFNumber" object that has
491
  //  the bits initialized to the provided values.
492
5
  ExplodedNode *N = C.generateNonFatalErrorNode();
493
5
  if (N) {
494
5
    SmallString<128> sbuf;
495
5
    llvm::raw_svector_ostream os(sbuf);
496
5
    bool isCreate = (FD->getIdentifier() == ICreate);
497
498
5
    if (isCreate) {
499
3
      os << (PrimitiveTypeSize == 8 ? 
"An "1
:
"A "2
)
500
3
         << PrimitiveTypeSize << "-bit integer is used to initialize a "
501
3
         << "CFNumber object that represents "
502
3
         << (CFNumberSize == 8 ? 
"an "1
:
"a "2
)
503
3
         << CFNumberSize << "-bit integer; ";
504
3
    } else {
505
2
      os << "A CFNumber object that represents "
506
2
         << (CFNumberSize == 8 ? 
"an "1
:
"a "1
)
507
2
         << CFNumberSize << "-bit integer is used to initialize "
508
2
         << (PrimitiveTypeSize == 8 ? 
"an "1
:
"a "1
)
509
2
         << PrimitiveTypeSize << "-bit integer; ";
510
2
    }
511
512
5
    if (PrimitiveTypeSize < CFNumberSize)
513
3
      os << (CFNumberSize - PrimitiveTypeSize)
514
3
      << " bits of the CFNumber value will "
515
3
      << (isCreate ? 
"be garbage."2
:
"overwrite adjacent storage."1
);
516
2
    else
517
2
      os << (PrimitiveTypeSize - CFNumberSize)
518
2
      << " bits of the integer value will be "
519
2
      << (isCreate ? 
"lost."1
:
"garbage."1
);
520
521
5
    if (!BT)
522
1
      BT.reset(new APIMisuse(this, "Bad use of CFNumber APIs"));
523
524
5
    auto report = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
525
5
    report->addRange(CE->getArg(2)->getSourceRange());
526
5
    C.emitReport(std::move(report));
527
5
  }
528
5
}
529
530
//===----------------------------------------------------------------------===//
531
// CFRetain/CFRelease/CFMakeCollectable/CFAutorelease checking for null arguments.
532
//===----------------------------------------------------------------------===//
533
534
namespace {
535
class CFRetainReleaseChecker : public Checker<check::PreCall> {
536
  mutable APIMisuse BT{this, "null passed to CF memory management function"};
537
  const CallDescriptionSet ModelledCalls = {
538
      {"CFRetain", 1},
539
      {"CFRelease", 1},
540
      {"CFMakeCollectable", 1},
541
      {"CFAutorelease", 1},
542
  };
543
544
public:
545
  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
546
};
547
} // end anonymous namespace
548
549
void CFRetainReleaseChecker::checkPreCall(const CallEvent &Call,
550
2.70k
                                          CheckerContext &C) const {
551
  // TODO: Make this check part of CallDescription.
552
2.70k
  if (!Call.isGlobalCFunction())
553
1.57k
    return;
554
555
  // Check if we called CFRetain/CFRelease/CFMakeCollectable/CFAutorelease.
556
1.12k
  if (!ModelledCalls.contains(Call))
557
890
    return;
558
559
  // Get the argument's value.
560
239
  SVal ArgVal = Call.getArgSVal(0);
561
239
  Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
562
239
  if (!DefArgVal)
563
0
    return;
564
565
  // Is it null?
566
239
  ProgramStateRef state = C.getState();
567
239
  ProgramStateRef stateNonNull, stateNull;
568
239
  std::tie(stateNonNull, stateNull) = state->assume(*DefArgVal);
569
570
239
  if (!stateNonNull) {
571
14
    ExplodedNode *N = C.generateErrorNode(stateNull);
572
14
    if (!N)
573
0
      return;
574
575
14
    SmallString<64> Str;
576
14
    raw_svector_ostream OS(Str);
577
14
    OS << "Null pointer argument in call to "
578
14
       << cast<FunctionDecl>(Call.getDecl())->getName();
579
580
14
    auto report = std::make_unique<PathSensitiveBugReport>(BT, OS.str(), N);
581
14
    report->addRange(Call.getArgSourceRange(0));
582
14
    bugreporter::trackExpressionValue(N, Call.getArgExpr(0), *report);
583
14
    C.emitReport(std::move(report));
584
14
    return;
585
14
  }
586
587
  // From here on, we know the argument is non-null.
588
225
  C.addTransition(stateNonNull);
589
225
}
590
591
//===----------------------------------------------------------------------===//
592
// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
593
//===----------------------------------------------------------------------===//
594
595
namespace {
596
class ClassReleaseChecker : public Checker<check::PreObjCMessage> {
597
  mutable Selector releaseS;
598
  mutable Selector retainS;
599
  mutable Selector autoreleaseS;
600
  mutable Selector drainS;
601
  mutable std::unique_ptr<BugType> BT;
602
603
public:
604
  void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
605
};
606
} // end anonymous namespace
607
608
void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
609
1.23k
                                              CheckerContext &C) const {
610
1.23k
  if (!BT) {
611
13
    BT.reset(new APIMisuse(
612
13
        this, "message incorrectly sent to class instead of class instance"));
613
614
13
    ASTContext &Ctx = C.getASTContext();
615
13
    releaseS = GetNullarySelector("release", Ctx);
616
13
    retainS = GetNullarySelector("retain", Ctx);
617
13
    autoreleaseS = GetNullarySelector("autorelease", Ctx);
618
13
    drainS = GetNullarySelector("drain", Ctx);
619
13
  }
620
621
1.23k
  if (msg.isInstanceMessage())
622
882
    return;
623
349
  const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
624
349
  assert(Class);
625
626
0
  Selector S = msg.getSelector();
627
349
  if (!(S == releaseS || 
S == retainS346
||
S == autoreleaseS343
||
S == drainS340
))
628
337
    return;
629
630
12
  if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
631
12
    SmallString<200> buf;
632
12
    llvm::raw_svector_ostream os(buf);
633
634
12
    os << "The '";
635
12
    S.print(os);
636
12
    os << "' message should be sent to instances "
637
12
          "of class '" << Class->getName()
638
12
       << "' and not the class directly";
639
640
12
    auto report = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
641
12
    report->addRange(msg.getSourceRange());
642
12
    C.emitReport(std::move(report));
643
12
  }
644
12
}
645
646
//===----------------------------------------------------------------------===//
647
// Check for passing non-Objective-C types to variadic methods that expect
648
// only Objective-C types.
649
//===----------------------------------------------------------------------===//
650
651
namespace {
652
class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> {
653
  mutable Selector arrayWithObjectsS;
654
  mutable Selector dictionaryWithObjectsAndKeysS;
655
  mutable Selector setWithObjectsS;
656
  mutable Selector orderedSetWithObjectsS;
657
  mutable Selector initWithObjectsS;
658
  mutable Selector initWithObjectsAndKeysS;
659
  mutable std::unique_ptr<BugType> BT;
660
661
  bool isVariadicMessage(const ObjCMethodCall &msg) const;
662
663
public:
664
  void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
665
};
666
} // end anonymous namespace
667
668
/// isVariadicMessage - Returns whether the given message is a variadic message,
669
/// where all arguments must be Objective-C types.
670
bool
671
62
VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
672
62
  const ObjCMethodDecl *MD = msg.getDecl();
673
674
62
  if (!MD || 
!MD->isVariadic()61
||
isa<ObjCProtocolDecl>(MD->getDeclContext())15
)
675
48
    return false;
676
677
14
  Selector S = msg.getSelector();
678
679
14
  if (msg.isInstanceMessage()) {
680
    // FIXME: Ideally we'd look at the receiver interface here, but that's not
681
    // useful for init, because alloc returns 'id'. In theory, this could lead
682
    // to false positives, for example if there existed a class that had an
683
    // initWithObjects: implementation that does accept non-Objective-C pointer
684
    // types, but the chance of that happening is pretty small compared to the
685
    // gains that this analysis gives.
686
8
    const ObjCInterfaceDecl *Class = MD->getClassInterface();
687
688
8
    switch (findKnownClass(Class)) {
689
1
    case FC_NSArray:
690
2
    case FC_NSOrderedSet:
691
3
    case FC_NSSet:
692
3
      return S == initWithObjectsS;
693
5
    case FC_NSDictionary:
694
5
      return S == initWithObjectsAndKeysS;
695
0
    default:
696
0
      return false;
697
8
    }
698
8
  } else {
699
6
    const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
700
701
6
    switch (findKnownClass(Class)) {
702
3
      case FC_NSArray:
703
3
        return S == arrayWithObjectsS;
704
1
      case FC_NSOrderedSet:
705
1
        return S == orderedSetWithObjectsS;
706
1
      case FC_NSSet:
707
1
        return S == setWithObjectsS;
708
1
      case FC_NSDictionary:
709
1
        return S == dictionaryWithObjectsAndKeysS;
710
0
      default:
711
0
        return false;
712
6
    }
713
6
  }
714
14
}
715
716
void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
717
62
                                                    CheckerContext &C) const {
718
62
  if (!BT) {
719
4
    BT.reset(new APIMisuse(this,
720
4
                           "Arguments passed to variadic method aren't all "
721
4
                           "Objective-C pointer types"));
722
723
4
    ASTContext &Ctx = C.getASTContext();
724
4
    arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
725
4
    dictionaryWithObjectsAndKeysS =
726
4
      GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
727
4
    setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
728
4
    orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx);
729
730
4
    initWithObjectsS = GetUnarySelector("initWithObjects", Ctx);
731
4
    initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx);
732
4
  }
733
734
62
  if (!isVariadicMessage(msg))
735
48
      return;
736
737
  // We are not interested in the selector arguments since they have
738
  // well-defined types, so the compiler will issue a warning for them.
739
14
  unsigned variadicArgsBegin = msg.getSelector().getNumArgs();
740
741
  // We're not interested in the last argument since it has to be nil or the
742
  // compiler would have issued a warning for it elsewhere.
743
14
  unsigned variadicArgsEnd = msg.getNumArgs() - 1;
744
745
14
  if (variadicArgsEnd <= variadicArgsBegin)
746
0
    return;
747
748
  // Verify that all arguments have Objective-C types.
749
14
  Optional<ExplodedNode*> errorNode;
750
751
32
  for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; 
++I18
) {
752
18
    QualType ArgTy = msg.getArgExpr(I)->getType();
753
18
    if (ArgTy->isObjCObjectPointerType())
754
4
      continue;
755
756
    // Block pointers are treaded as Objective-C pointers.
757
14
    if (ArgTy->isBlockPointerType())
758
1
      continue;
759
760
    // Ignore pointer constants.
761
13
    if (msg.getArgSVal(I).getAs<loc::ConcreteInt>())
762
1
      continue;
763
764
    // Ignore pointer types annotated with 'NSObject' attribute.
765
12
    if (C.getASTContext().isObjCNSObjectType(ArgTy))
766
1
      continue;
767
768
    // Ignore CF references, which can be toll-free bridged.
769
11
    if (coreFoundation::isCFObjectRef(ArgTy))
770
1
      continue;
771
772
    // Generate only one error node to use for all bug reports.
773
10
    if (!errorNode.hasValue())
774
9
      errorNode = C.generateNonFatalErrorNode();
775
776
10
    if (!errorNode.getValue())
777
0
      continue;
778
779
10
    SmallString<128> sbuf;
780
10
    llvm::raw_svector_ostream os(sbuf);
781
782
10
    StringRef TypeName = GetReceiverInterfaceName(msg);
783
10
    if (!TypeName.empty())
784
10
      os << "Argument to '" << TypeName << "' method '";
785
0
    else
786
0
      os << "Argument to method '";
787
788
10
    msg.getSelector().print(os);
789
10
    os << "' should be an Objective-C pointer type, not '";
790
10
    ArgTy.print(os, C.getLangOpts());
791
10
    os << "'";
792
793
10
    auto R = std::make_unique<PathSensitiveBugReport>(*BT, os.str(),
794
10
                                                      errorNode.getValue());
795
10
    R->addRange(msg.getArgSourceRange(I));
796
10
    C.emitReport(std::move(R));
797
10
  }
798
14
}
799
800
//===----------------------------------------------------------------------===//
801
// Improves the modeling of loops over Cocoa collections.
802
//===----------------------------------------------------------------------===//
803
804
// The map from container symbol to the container count symbol.
805
// We currently will remember the last container count symbol encountered.
806
REGISTER_MAP_WITH_PROGRAMSTATE(ContainerCountMap, SymbolRef, SymbolRef)
807
REGISTER_MAP_WITH_PROGRAMSTATE(ContainerNonEmptyMap, SymbolRef, bool)
808
809
namespace {
810
class ObjCLoopChecker
811
  : public Checker<check::PostStmt<ObjCForCollectionStmt>,
812
                   check::PostObjCMessage,
813
                   check::DeadSymbols,
814
                   check::PointerEscape > {
815
  mutable IdentifierInfo *CountSelectorII;
816
817
  bool isCollectionCountMethod(const ObjCMethodCall &M,
818
                               CheckerContext &C) const;
819
820
public:
821
48
  ObjCLoopChecker() : CountSelectorII(nullptr) {}
822
  void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const;
823
  void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
824
  void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
825
  ProgramStateRef checkPointerEscape(ProgramStateRef State,
826
                                     const InvalidatedSymbols &Escaped,
827
                                     const CallEvent *Call,
828
                                     PointerEscapeKind Kind) const;
829
};
830
} // end anonymous namespace
831
832
226
static bool isKnownNonNilCollectionType(QualType T) {
833
226
  const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
834
226
  if (!PT)
835
0
    return false;
836
837
226
  const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
838
226
  if (!ID)
839
2
    return false;
840
841
224
  switch (findKnownClass(ID)) {
842
29
  case FC_NSArray:
843
99
  case FC_NSDictionary:
844
131
  case FC_NSEnumerator:
845
134
  case FC_NSOrderedSet:
846
154
  case FC_NSSet:
847
154
    return true;
848
70
  default:
849
70
    return false;
850
224
  }
851
224
}
852
853
/// Assumes that the collection is non-nil.
854
///
855
/// If the collection is known to be nil, returns NULL to indicate an infeasible
856
/// path.
857
static ProgramStateRef checkCollectionNonNil(CheckerContext &C,
858
                                             ProgramStateRef State,
859
226
                                             const ObjCForCollectionStmt *FCS) {
860
226
  if (!State)
861
0
    return nullptr;
862
863
226
  SVal CollectionVal = C.getSVal(FCS->getCollection());
864
226
  Optional<DefinedSVal> KnownCollection = CollectionVal.getAs<DefinedSVal>();
865
226
  if (!KnownCollection)
866
0
    return State;
867
868
226
  ProgramStateRef StNonNil, StNil;
869
226
  std::tie(StNonNil, StNil) = State->assume(*KnownCollection);
870
226
  if (StNil && 
!StNonNil41
) {
871
    // The collection is nil. This path is infeasible.
872
0
    return nullptr;
873
0
  }
874
875
226
  return StNonNil;
876
226
}
877
878
/// Assumes that the collection elements are non-nil.
879
///
880
/// This only applies if the collection is one of those known not to contain
881
/// nil values.
882
static ProgramStateRef checkElementNonNil(CheckerContext &C,
883
                                          ProgramStateRef State,
884
226
                                          const ObjCForCollectionStmt *FCS) {
885
226
  if (!State)
886
0
    return nullptr;
887
888
  // See if the collection is one where we /know/ the elements are non-nil.
889
226
  if (!isKnownNonNilCollectionType(FCS->getCollection()->getType()))
890
72
    return State;
891
892
154
  const LocationContext *LCtx = C.getLocationContext();
893
154
  const Stmt *Element = FCS->getElement();
894
895
  // FIXME: Copied from ExprEngineObjC.
896
154
  Optional<Loc> ElementLoc;
897
154
  if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
898
94
    const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
899
94
    assert(ElemDecl->getInit() == nullptr);
900
0
    ElementLoc = State->getLValue(ElemDecl, LCtx);
901
94
  } else {
902
60
    ElementLoc = State->getSVal(Element, LCtx).getAs<Loc>();
903
60
  }
904
905
154
  if (!ElementLoc)
906
0
    return State;
907
908
  // Go ahead and assume the value is non-nil.
909
154
  SVal Val = State->getSVal(*ElementLoc);
910
154
  return State->assume(Val.castAs<DefinedOrUnknownSVal>(), true);
911
154
}
912
913
/// Returns NULL state if the collection is known to contain elements
914
/// (or is known not to contain elements if the Assumption parameter is false.)
915
static ProgramStateRef
916
assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
917
317
                         SymbolRef CollectionS, bool Assumption) {
918
317
  if (!State || !CollectionS)
919
3
    return State;
920
921
314
  const SymbolRef *CountS = State->get<ContainerCountMap>(CollectionS);
922
314
  if (!CountS) {
923
224
    const bool *KnownNonEmpty = State->get<ContainerNonEmptyMap>(CollectionS);
924
224
    if (!KnownNonEmpty)
925
94
      return State->set<ContainerNonEmptyMap>(CollectionS, Assumption);
926
130
    return (Assumption == *KnownNonEmpty) ? 
State124
:
nullptr6
;
927
224
  }
928
929
90
  SValBuilder &SvalBuilder = C.getSValBuilder();
930
90
  SVal CountGreaterThanZeroVal =
931
90
    SvalBuilder.evalBinOp(State, BO_GT,
932
90
                          nonloc::SymbolVal(*CountS),
933
90
                          SvalBuilder.makeIntVal(0, (*CountS)->getType()),
934
90
                          SvalBuilder.getConditionType());
935
90
  Optional<DefinedSVal> CountGreaterThanZero =
936
90
    CountGreaterThanZeroVal.getAs<DefinedSVal>();
937
90
  if (!CountGreaterThanZero) {
938
    // The SValBuilder cannot construct a valid SVal for this condition.
939
    // This means we cannot properly reason about it.
940
0
    return State;
941
0
  }
942
943
90
  return State->assume(*CountGreaterThanZero, Assumption);
944
90
}
945
946
static ProgramStateRef
947
assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
948
                         const ObjCForCollectionStmt *FCS,
949
309
                         bool Assumption) {
950
309
  if (!State)
951
0
    return nullptr;
952
953
309
  SymbolRef CollectionS = C.getSVal(FCS->getCollection()).getAsSymbol();
954
309
  return assumeCollectionNonEmpty(C, State, CollectionS, Assumption);
955
309
}
956
957
/// If the fist block edge is a back edge, we are reentering the loop.
958
static bool alreadyExecutedAtLeastOneLoopIteration(const ExplodedNode *N,
959
1.27k
                                             const ObjCForCollectionStmt *FCS) {
960
1.27k
  if (!N)
961
0
    return false;
962
963
1.27k
  ProgramPoint P = N->getLocation();
964
1.27k
  if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
965
197
    return BE->getSrc()->getLoopTarget() == FCS;
966
197
  }
967
968
  // Keep looking for a block edge.
969
1.07k
  for (ExplodedNode::const_pred_iterator I = N->pred_begin(),
970
1.52k
                                         E = N->pred_end(); I != E; 
++I446
) {
971
1.07k
    if (alreadyExecutedAtLeastOneLoopIteration(*I, FCS))
972
631
      return true;
973
1.07k
  }
974
975
446
  return false;
976
1.07k
}
977
978
void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
979
423
                                    CheckerContext &C) const {
980
423
  ProgramStateRef State = C.getState();
981
982
  // Check if this is the branch for the end of the loop.
983
423
  if (!ExprEngine::hasMoreIteration(State, FCS, C.getLocationContext())) {
984
197
    if (!alreadyExecutedAtLeastOneLoopIteration(C.getPredecessor(), FCS))
985
83
      State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/false);
986
987
  // Otherwise, this is a branch that goes through the loop body.
988
226
  } else {
989
226
    State = checkCollectionNonNil(C, State, FCS);
990
226
    State = checkElementNonNil(C, State, FCS);
991
226
    State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/true);
992
226
  }
993
994
423
  if (!State)
995
31
    C.generateSink(C.getState(), C.getPredecessor());
996
392
  else if (State != C.getState())
997
208
    C.addTransition(State);
998
423
}
999
1000
bool ObjCLoopChecker::isCollectionCountMethod(const ObjCMethodCall &M,
1001
60
                                              CheckerContext &C) const {
1002
60
  Selector S = M.getSelector();
1003
  // Initialize the identifiers on first use.
1004
60
  if (!CountSelectorII)
1005
2
    CountSelectorII = &C.getASTContext().Idents.get("count");
1006
1007
  // If the method returns collection count, record the value.
1008
60
  return S.isUnarySelector() &&
1009
60
         
(S.getIdentifierInfoForSlot(0) == CountSelectorII)43
;
1010
60
}
1011
1012
void ObjCLoopChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1013
142
                                           CheckerContext &C) const {
1014
142
  if (!M.isInstanceMessage())
1015
44
    return;
1016
1017
98
  const ObjCInterfaceDecl *ClassID = M.getReceiverInterface();
1018
98
  if (!ClassID)
1019
0
    return;
1020
1021
98
  FoundationClass Class = findKnownClass(ClassID);
1022
98
  if (Class != FC_NSDictionary &&
1023
98
      
Class != FC_NSArray74
&&
1024
98
      
Class != FC_NSSet40
&&
1025
98
      
Class != FC_NSOrderedSet39
)
1026
38
    return;
1027
1028
60
  SymbolRef ContainerS = M.getReceiverSVal().getAsSymbol();
1029
60
  if (!ContainerS)
1030
0
    return;
1031
1032
  // If we are processing a call to "count", get the symbolic value returned by
1033
  // a call to "count" and add it to the map.
1034
60
  if (!isCollectionCountMethod(M, C))
1035
36
    return;
1036
1037
24
  const Expr *MsgExpr = M.getOriginExpr();
1038
24
  SymbolRef CountS = C.getSVal(MsgExpr).getAsSymbol();
1039
24
  if (CountS) {
1040
24
    ProgramStateRef State = C.getState();
1041
1042
24
    C.getSymbolManager().addSymbolDependency(ContainerS, CountS);
1043
24
    State = State->set<ContainerCountMap>(ContainerS, CountS);
1044
1045
24
    if (const bool *NonEmpty = State->get<ContainerNonEmptyMap>(ContainerS)) {
1046
8
      State = State->remove<ContainerNonEmptyMap>(ContainerS);
1047
8
      State = assumeCollectionNonEmpty(C, State, ContainerS, *NonEmpty);
1048
8
    }
1049
1050
24
    C.addTransition(State);
1051
24
  }
1052
24
}
1053
1054
394
static SymbolRef getMethodReceiverIfKnownImmutable(const CallEvent *Call) {
1055
394
  const ObjCMethodCall *Message = dyn_cast_or_null<ObjCMethodCall>(Call);
1056
394
  if (!Message)
1057
242
    return nullptr;
1058
1059
152
  const ObjCMethodDecl *MD = Message->getDecl();
1060
152
  if (!MD)
1061
1
    return nullptr;
1062
1063
151
  const ObjCInterfaceDecl *StaticClass;
1064
151
  if (isa<ObjCProtocolDecl>(MD->getDeclContext())) {
1065
    // We can't find out where the method was declared without doing more work.
1066
    // Instead, see if the receiver is statically typed as a known immutable
1067
    // collection.
1068
4
    StaticClass = Message->getOriginExpr()->getReceiverInterface();
1069
147
  } else {
1070
147
    StaticClass = MD->getClassInterface();
1071
147
  }
1072
1073
151
  if (!StaticClass)
1074
0
    return nullptr;
1075
1076
151
  switch (findKnownClass(StaticClass, /*IncludeSuper=*/false)) {
1077
96
  case FC_None:
1078
96
    return nullptr;
1079
35
  case FC_NSArray:
1080
53
  case FC_NSDictionary:
1081
53
  case FC_NSEnumerator:
1082
53
  case FC_NSNull:
1083
54
  case FC_NSOrderedSet:
1084
55
  case FC_NSSet:
1085
55
  case FC_NSString:
1086
55
    break;
1087
151
  }
1088
1089
55
  return Message->getReceiverSVal().getAsSymbol();
1090
151
}
1091
1092
ProgramStateRef
1093
ObjCLoopChecker::checkPointerEscape(ProgramStateRef State,
1094
                                    const InvalidatedSymbols &Escaped,
1095
                                    const CallEvent *Call,
1096
394
                                    PointerEscapeKind Kind) const {
1097
394
  SymbolRef ImmutableReceiver = getMethodReceiverIfKnownImmutable(Call);
1098
1099
  // Remove the invalidated symbols form the collection count map.
1100
394
  for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
1101
394
       E = Escaped.end();
1102
976
       I != E; 
++I582
) {
1103
582
    SymbolRef Sym = *I;
1104
1105
    // Don't invalidate this symbol's count if we know the method being called
1106
    // is declared on an immutable class. This isn't completely correct if the
1107
    // receiver is also passed as an argument, but in most uses of NSArray,
1108
    // NSDictionary, etc. this isn't likely to happen in a dangerous way.
1109
582
    if (Sym == ImmutableReceiver)
1110
37
      continue;
1111
1112
    // The symbol escaped. Pessimistically, assume that the count could have
1113
    // changed.
1114
545
    State = State->remove<ContainerCountMap>(Sym);
1115
545
    State = State->remove<ContainerNonEmptyMap>(Sym);
1116
545
  }
1117
394
  return State;
1118
394
}
1119
1120
void ObjCLoopChecker::checkDeadSymbols(SymbolReaper &SymReaper,
1121
2.87k
                                       CheckerContext &C) const {
1122
2.87k
  ProgramStateRef State = C.getState();
1123
1124
  // Remove the dead symbols from the collection count map.
1125
2.87k
  ContainerCountMapTy Tracked = State->get<ContainerCountMap>();
1126
2.87k
  for (ContainerCountMapTy::iterator I = Tracked.begin(),
1127
3.21k
                                     E = Tracked.end(); I != E; 
++I336
) {
1128
336
    SymbolRef Sym = I->first;
1129
336
    if (SymReaper.isDead(Sym)) {
1130
43
      State = State->remove<ContainerCountMap>(Sym);
1131
43
      State = State->remove<ContainerNonEmptyMap>(Sym);
1132
43
    }
1133
336
  }
1134
1135
2.87k
  C.addTransition(State);
1136
2.87k
}
1137
1138
namespace {
1139
/// \class ObjCNonNilReturnValueChecker
1140
/// The checker restricts the return values of APIs known to
1141
/// never (or almost never) return 'nil'.
1142
class ObjCNonNilReturnValueChecker
1143
  : public Checker<check::PostObjCMessage,
1144
                   check::PostStmt<ObjCArrayLiteral>,
1145
                   check::PostStmt<ObjCDictionaryLiteral>,
1146
                   check::PostStmt<ObjCBoxedExpr> > {
1147
    mutable bool Initialized;
1148
    mutable Selector ObjectAtIndex;
1149
    mutable Selector ObjectAtIndexedSubscript;
1150
    mutable Selector NullSelector;
1151
1152
public:
1153
49
  ObjCNonNilReturnValueChecker() : Initialized(false) {}
1154
1155
  ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
1156
                                      ProgramStateRef State,
1157
                                      CheckerContext &C) const;
1158
16
  void assumeExprIsNonNull(const Expr *E, CheckerContext &C) const {
1159
16
    C.addTransition(assumeExprIsNonNull(E, C.getState(), C));
1160
16
  }
1161
1162
2
  void checkPostStmt(const ObjCArrayLiteral *E, CheckerContext &C) const {
1163
2
    assumeExprIsNonNull(E, C);
1164
2
  }
1165
4
  void checkPostStmt(const ObjCDictionaryLiteral *E, CheckerContext &C) const {
1166
4
    assumeExprIsNonNull(E, C);
1167
4
  }
1168
10
  void checkPostStmt(const ObjCBoxedExpr *E, CheckerContext &C) const {
1169
10
    assumeExprIsNonNull(E, C);
1170
10
  }
1171
1172
  void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
1173
};
1174
} // end anonymous namespace
1175
1176
ProgramStateRef
1177
ObjCNonNilReturnValueChecker::assumeExprIsNonNull(const Expr *NonNullExpr,
1178
                                                  ProgramStateRef State,
1179
22
                                                  CheckerContext &C) const {
1180
22
  SVal Val = C.getSVal(NonNullExpr);
1181
22
  if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>())
1182
22
    return State->assume(*DV, true);
1183
0
  return State;
1184
22
}
1185
1186
void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
1187
                                                        CheckerContext &C)
1188
73
                                                        const {
1189
73
  ProgramStateRef State = C.getState();
1190
1191
73
  if (!Initialized) {
1192
73
    ASTContext &Ctx = C.getASTContext();
1193
73
    ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
1194
73
    ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
1195
73
    NullSelector = GetNullarySelector("null", Ctx);
1196
73
  }
1197
1198
  // Check the receiver type.
1199
73
  if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
1200
1201
    // Assume that object returned from '[self init]' or '[super init]' is not
1202
    // 'nil' if we are processing an inlined function/method.
1203
    //
1204
    // A defensive callee will (and should) check if the object returned by
1205
    // '[super init]' is 'nil' before doing it's own initialization. However,
1206
    // since 'nil' is rarely returned in practice, we should not warn when the
1207
    // caller to the defensive constructor uses the object in contexts where
1208
    // 'nil' is not accepted.
1209
73
    if (!C.inTopFrame() && 
M.getDecl()2
&&
1210
73
        
M.getDecl()->getMethodFamily() == OMF_init1
&&
1211
73
        
M.isReceiverSelfOrSuper()1
) {
1212
1
      State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1213
1
    }
1214
1215
73
    FoundationClass Cl = findKnownClass(Interface);
1216
1217
    // Objects returned from
1218
    // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
1219
    // are never 'nil'.
1220
73
    if (Cl == FC_NSArray || 
Cl == FC_NSOrderedSet55
) {
1221
20
      Selector Sel = M.getSelector();
1222
20
      if (Sel == ObjectAtIndex || 
Sel == ObjectAtIndexedSubscript18
) {
1223
        // Go ahead and assume the value is non-nil.
1224
4
        State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1225
4
      }
1226
20
    }
1227
1228
    // Objects returned from [NSNull null] are not nil.
1229
73
    if (Cl == FC_NSNull) {
1230
1
      if (M.getSelector() == NullSelector) {
1231
        // Go ahead and assume the value is non-nil.
1232
1
        State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
1233
1
      }
1234
1
    }
1235
73
  }
1236
73
  C.addTransition(State);
1237
73
}
1238
1239
//===----------------------------------------------------------------------===//
1240
// Check registration.
1241
//===----------------------------------------------------------------------===//
1242
1243
53
void ento::registerNilArgChecker(CheckerManager &mgr) {
1244
53
  mgr.registerChecker<NilArgChecker>();
1245
53
}
1246
1247
106
bool ento::shouldRegisterNilArgChecker(const CheckerManager &mgr) {
1248
106
  return true;
1249
106
}
1250
1251
47
void ento::registerCFNumberChecker(CheckerManager &mgr) {
1252
47
  mgr.registerChecker<CFNumberChecker>();
1253
47
}
1254
1255
94
bool ento::shouldRegisterCFNumberChecker(const CheckerManager &mgr) {
1256
94
  return true;
1257
94
}
1258
1259
57
void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) {
1260
57
  mgr.registerChecker<CFRetainReleaseChecker>();
1261
57
}
1262
1263
114
bool ento::shouldRegisterCFRetainReleaseChecker(const CheckerManager &mgr) {
1264
114
  return true;
1265
114
}
1266
1267
55
void ento::registerClassReleaseChecker(CheckerManager &mgr) {
1268
55
  mgr.registerChecker<ClassReleaseChecker>();
1269
55
}
1270
1271
110
bool ento::shouldRegisterClassReleaseChecker(const CheckerManager &mgr) {
1272
110
  return true;
1273
110
}
1274
1275
47
void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) {
1276
47
  mgr.registerChecker<VariadicMethodTypeChecker>();
1277
47
}
1278
1279
94
bool ento::shouldRegisterVariadicMethodTypeChecker(const CheckerManager &mgr) {
1280
94
  return true;
1281
94
}
1282
1283
48
void ento::registerObjCLoopChecker(CheckerManager &mgr) {
1284
48
  mgr.registerChecker<ObjCLoopChecker>();
1285
48
}
1286
1287
96
bool ento::shouldRegisterObjCLoopChecker(const CheckerManager &mgr) {
1288
96
  return true;
1289
96
}
1290
1291
49
void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) {
1292
49
  mgr.registerChecker<ObjCNonNilReturnValueChecker>();
1293
49
}
1294
1295
98
bool ento::shouldRegisterObjCNonNilReturnValueChecker(const CheckerManager &mgr) {
1296
98
  return true;
1297
98
}