Coverage Report

Created: 2019-07-24 05:18

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