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