1 // RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,debug.ExprInspection -analyzer-store=region -verify -Wno-objc-root-class %s 2 // RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,debug.ExprInspection -analyzer-store=region -verify -Wno-objc-root-class -fobjc-arc %s 3 4 void clang_analyzer_eval(int); 5 6 typedef const void * CFTypeRef; 7 extern CFTypeRef CFRetain(CFTypeRef cf); 8 void CFRelease(CFTypeRef cf); 9 10 typedef signed char BOOL; 11 typedef unsigned int NSUInteger; 12 typedef struct _NSZone NSZone; 13 @class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; 14 @protocol NSObject - (BOOL)isEqual:(id)object; @end 15 @protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end 16 @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end 17 @protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; @end 18 @interface NSObject <NSObject> {} 19 +(id)alloc; 20 -(id)init; 21 -(id)autorelease; 22 -(id)copy; 23 -(id)retain; 24 -(oneway void)release; 25 @end 26 @interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> 27 - (NSUInteger)length; 28 -(id)initWithFormat:(NSString *)f,...; 29 -(BOOL)isEqualToString:(NSString *)s; 30 + (id)string; 31 @end 32 @interface NSNumber : NSObject {} 33 +(id)alloc; 34 -(id)initWithInteger:(int)i; 35 @end 36 37 // rdar://6946338 38 39 @interface Test1 : NSObject { 40 NSString *text; 41 } 42 -(id)myMethod; 43 @property (nonatomic, assign) NSString *text; 44 @end 45 46 47 #if !__has_feature(objc_arc) 48 49 @implementation Test1 50 51 @synthesize text; 52 53 -(id)myMethod { 54 Test1 *cell = [[[Test1 alloc] init] autorelease]; 55 56 NSString *string1 = [[NSString alloc] initWithFormat:@"test %f", 0.0]; // expected-warning {{Potential leak}} 57 cell.text = string1; 58 59 return cell; 60 } 61 62 @end 63 64 65 // rdar://8824416 66 67 @interface MyNumber : NSObject 68 { 69 NSNumber* _myNumber; 70 } 71 72 - (id)initWithNumber:(NSNumber *)number; 73 74 @property (nonatomic, readonly) NSNumber* myNumber; 75 @property (nonatomic, readonly) NSNumber* newMyNumber; 76 77 @end 78 79 @implementation MyNumber 80 @synthesize myNumber=_myNumber; 81 82 - (id)initWithNumber:(NSNumber *)number 83 { 84 self = [super init]; 85 86 if ( self ) 87 { 88 _myNumber = [number copy]; 89 } 90 91 return self; 92 } 93 94 - (NSNumber*)newMyNumber 95 { 96 if ( _myNumber ) 97 return [_myNumber retain]; 98 99 return [[NSNumber alloc] initWithInteger:1]; 100 } 101 102 - (id)valueForUndefinedKey:(NSString*)key 103 { 104 id value = 0; 105 106 if ([key isEqualToString:@"MyIvarNumberAsPropertyOverReleased"]) 107 value = self.myNumber; // _myNumber will be over released, since the value returned from self.myNumber is not retained. 108 else if ([key isEqualToString:@"MyIvarNumberAsPropertyOk"]) 109 value = [self.myNumber retain]; // this line fixes the over release 110 else if ([key isEqualToString:@"MyIvarNumberAsNewMyNumber"]) 111 value = self.newMyNumber; // this one is ok, since value is returned retained 112 else 113 value = [[NSNumber alloc] initWithInteger:0]; 114 115 return [value autorelease]; // expected-warning {{Object autoreleased too many times}} 116 } 117 118 @end 119 120 NSNumber* numberFromMyNumberProperty(MyNumber* aMyNumber) 121 { 122 NSNumber* result = aMyNumber.myNumber; 123 124 return [result autorelease]; // expected-warning {{Object autoreleased too many times}} 125 } 126 127 #endif 128 129 130 // rdar://6611873 131 132 @interface Person : NSObject { 133 NSString *_name; 134 } 135 @property (retain) NSString * name; 136 @property (assign) id friend; 137 @end 138 139 @implementation Person 140 @synthesize name = _name; 141 @end 142 143 #if !__has_feature(objc_arc) 144 void rdar6611873() { 145 Person *p = [[[Person alloc] init] autorelease]; 146 147 p.name = [[NSString string] retain]; // expected-warning {{leak}} 148 p.name = [[NSString alloc] init]; // expected-warning {{leak}} 149 150 p.friend = [[Person alloc] init]; // expected-warning {{leak}} 151 } 152 #endif 153 154 @interface SubPerson : Person 155 -(NSString *)foo; 156 @end 157 158 @implementation SubPerson 159 -(NSString *)foo { 160 return super.name; 161 } 162 @end 163 164 165 #if !__has_feature(objc_arc) 166 // <rdar://problem/9241180> Static analyzer doesn't detect uninitialized variable issues for property accesses 167 @interface RDar9241180 168 @property (readwrite,assign) id x; 169 -(id)testAnalyzer1:(int) y; 170 -(void)testAnalyzer2; 171 @end 172 173 @implementation RDar9241180 174 @synthesize x; 175 -(id)testAnalyzer1:(int)y { 176 RDar9241180 *o; 177 if (y && o.x) // expected-warning {{Property access on an uninitialized object pointer}} 178 return o; 179 return o; // expected-warning {{Undefined or garbage value returned to caller}} 180 } 181 -(void)testAnalyzer2 { 182 id y; 183 self.x = y; // expected-warning {{Argument for property setter is an uninitialized value}} 184 } 185 @end 186 #endif 187 188 189 //------ 190 // Property accessor synthesis 191 //------ 192 193 extern void doSomethingWithPerson(Person *p); 194 extern void doSomethingWithName(NSString *name); 195 196 void testConsistencyRetain(Person *p) { 197 clang_analyzer_eval(p.name == p.name); // expected-warning{{TRUE}} 198 199 id origName = p.name; 200 clang_analyzer_eval(p.name == origName); // expected-warning{{TRUE}} 201 doSomethingWithPerson(p); 202 clang_analyzer_eval(p.name == origName); // expected-warning{{UNKNOWN}} 203 } 204 205 void testConsistencyAssign(Person *p) { 206 clang_analyzer_eval(p.friend == p.friend); // expected-warning{{TRUE}} 207 208 id origFriend = p.friend; 209 clang_analyzer_eval(p.friend == origFriend); // expected-warning{{TRUE}} 210 doSomethingWithPerson(p); 211 clang_analyzer_eval(p.friend == origFriend); // expected-warning{{UNKNOWN}} 212 } 213 214 #if !__has_feature(objc_arc) 215 void testOverrelease(Person *p, int coin) { 216 switch (coin) { 217 case 0: 218 [p.name release]; // expected-warning{{not owned}} 219 break; 220 case 1: 221 [p.friend release]; // expected-warning{{not owned}} 222 break; 223 case 2: { 224 id friend = p.friend; 225 doSomethingWithPerson(p); 226 [friend release]; // expected-warning{{not owned}} 227 } 228 } 229 } 230 231 // <rdar://problem/16333368> 232 @implementation Person (Rdar16333368) 233 234 - (void)testDeliberateRelease:(Person *)other { 235 doSomethingWithName(self.name); 236 [_name release]; // no-warning 237 self->_name = 0; 238 239 doSomethingWithName(other->_name); 240 [other.name release]; // no-warning 241 } 242 243 - (void)deliberateReleaseFalseNegative { 244 // This is arguably a false negative because the result of p.friend shouldn't 245 // be released, even though we are manipulating the ivar in between the two 246 // actions. 247 id name = self.name; 248 _name = 0; 249 [name release]; 250 } 251 252 - (void)testRetainAndRelease { 253 [self.name retain]; 254 [self.name release]; 255 [self.name release]; // expected-warning{{not owned}} 256 } 257 258 - (void)testRetainAndReleaseIVar { 259 [self.name retain]; 260 [_name release]; 261 [_name release]; 262 } 263 264 @end 265 #endif 266 267 @interface IntWrapper 268 @property int value; 269 @end 270 271 @implementation IntWrapper 272 @synthesize value; 273 @end 274 275 void testConsistencyInt(IntWrapper *w) { 276 clang_analyzer_eval(w.value == w.value); // expected-warning{{TRUE}} 277 278 int origValue = w.value; 279 if (origValue != 42) 280 return; 281 282 clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}} 283 } 284 285 void testConsistencyInt2(IntWrapper *w) { 286 if (w.value != 42) 287 return; 288 289 clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}} 290 } 291 292 293 @interface IntWrapperAuto 294 @property int value; 295 @end 296 297 @implementation IntWrapperAuto 298 @end 299 300 void testConsistencyIntAuto(IntWrapperAuto *w) { 301 clang_analyzer_eval(w.value == w.value); // expected-warning{{TRUE}} 302 303 int origValue = w.value; 304 if (origValue != 42) 305 return; 306 307 clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}} 308 } 309 310 void testConsistencyIntAuto2(IntWrapperAuto *w) { 311 if (w.value != 42) 312 return; 313 314 clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}} 315 } 316 317 318 typedef struct { 319 int value; 320 } IntWrapperStruct; 321 322 @interface StructWrapper 323 @property IntWrapperStruct inner; 324 @end 325 326 @implementation StructWrapper 327 @synthesize inner; 328 @end 329 330 void testConsistencyStruct(StructWrapper *w) { 331 clang_analyzer_eval(w.inner.value == w.inner.value); // expected-warning{{TRUE}} 332 333 int origValue = w.inner.value; 334 if (origValue != 42) 335 return; 336 337 clang_analyzer_eval(w.inner.value == 42); // expected-warning{{TRUE}} 338 } 339 340 341 @interface OpaqueIntWrapper 342 @property int value; 343 @end 344 345 // For now, don't assume a property is implemented using an ivar unless we can 346 // actually see that it is. 347 void testOpaqueConsistency(OpaqueIntWrapper *w) { 348 clang_analyzer_eval(w.value == w.value); // expected-warning{{UNKNOWN}} 349 } 350 351 352 #if !__has_feature(objc_arc) 353 // Test quite a few cases of retain/release issues. 354 355 @interface RetainCountTesting 356 @property (strong) id ownedProp; 357 @property (unsafe_unretained) id unownedProp; 358 @property (nonatomic, strong) id manualProp; 359 @property (readonly) id readonlyProp; 360 @property (nonatomic, readwrite/*, assign */) id implicitManualProp; // expected-warning {{'assign' is assumed}} expected-warning {{'assign' not appropriate}} 361 @property (nonatomic, readwrite/*, assign */) id implicitSynthProp; // expected-warning {{'assign' is assumed}} expected-warning {{'assign' not appropriate}} 362 @property CFTypeRef cfProp; 363 @end 364 365 @implementation RetainCountTesting { 366 id _ivarOnly; 367 } 368 369 - (id)manualProp { 370 return _manualProp; 371 } 372 373 - (void)setImplicitManualProp:(id)newValue {} 374 375 - (void)testOverreleaseOwnedIvar { 376 [_ownedProp retain]; 377 [_ownedProp release]; 378 [_ownedProp release]; 379 [_ownedProp release]; // FIXME-warning{{used after it is released}} 380 } 381 382 - (void)testOverreleaseUnownedIvar { 383 [_unownedProp retain]; 384 [_unownedProp release]; 385 [_unownedProp release]; // FIXME-warning{{not owned at this point by the caller}} 386 } 387 388 - (void)testOverreleaseIvarOnly { 389 [_ivarOnly retain]; 390 [_ivarOnly release]; 391 [_ivarOnly release]; 392 [_ivarOnly release]; // FIXME-warning{{used after it is released}} 393 } 394 395 - (void)testOverreleaseReadonlyIvar { 396 [_readonlyProp retain]; 397 [_readonlyProp release]; 398 [_readonlyProp release]; 399 [_readonlyProp release]; // FIXME-warning{{used after it is released}} 400 } 401 402 - (void)testOverreleaseImplicitManualIvar { 403 [_implicitManualProp retain]; 404 [_implicitManualProp release]; 405 [_implicitManualProp release]; 406 [_implicitManualProp release]; // FIXME-warning{{used after it is released}} 407 } 408 409 - (void)testOverreleaseImplicitSynthIvar { 410 [_implicitSynthProp retain]; 411 [_implicitSynthProp release]; 412 [_implicitSynthProp release]; // FIXME-warning{{not owned at this point by the caller}} 413 } 414 415 - (void)testOverreleaseCF { 416 CFRetain(_cfProp); 417 CFRelease(_cfProp); 418 CFRelease(_cfProp); 419 CFRelease(_cfProp); // FIXME-warning{{used after it is released}} 420 } 421 422 - (void)testOverreleaseOwnedIvarUse { 423 [_ownedProp retain]; 424 [_ownedProp release]; 425 [_ownedProp release]; 426 [_ownedProp myMethod]; // FIXME-warning{{used after it is released}} 427 } 428 429 - (void)testOverreleaseIvarOnlyUse { 430 [_ivarOnly retain]; 431 [_ivarOnly release]; 432 [_ivarOnly release]; 433 [_ivarOnly myMethod]; // FIXME-warning{{used after it is released}} 434 } 435 436 - (void)testOverreleaseCFUse { 437 CFRetain(_cfProp); 438 CFRelease(_cfProp); 439 CFRelease(_cfProp); 440 441 extern void CFUse(CFTypeRef); 442 CFUse(_cfProp); // FIXME-warning{{used after it is released}} 443 } 444 445 - (void)testOverreleaseOwnedIvarAutoreleaseOkay { 446 [_ownedProp retain]; 447 [_ownedProp release]; 448 [_ownedProp autorelease]; 449 } // no-warning 450 451 - (void)testOverreleaseIvarOnlyAutoreleaseOkay { 452 [_ivarOnly retain]; 453 [_ivarOnly release]; 454 [_ivarOnly autorelease]; 455 } // no-warning 456 457 - (void)testOverreleaseOwnedIvarAutorelease { 458 [_ownedProp retain]; 459 [_ownedProp release]; 460 [_ownedProp autorelease]; 461 [_ownedProp autorelease]; 462 } // FIXME-warning{{Object autoreleased too many times}} 463 464 - (void)testOverreleaseIvarOnlyAutorelease { 465 [_ivarOnly retain]; 466 [_ivarOnly release]; 467 [_ivarOnly autorelease]; 468 [_ivarOnly autorelease]; 469 } // FIXME-warning{{Object autoreleased too many times}} 470 471 - (void)testPropertyAccessThenReleaseOwned { 472 id owned = [self.ownedProp retain]; 473 [owned release]; 474 [_ownedProp release]; 475 clang_analyzer_eval(owned == _ownedProp); // expected-warning{{TRUE}} 476 } 477 478 - (void)testPropertyAccessThenReleaseOwned2 { 479 id fromIvar = _ownedProp; 480 id owned = [self.ownedProp retain]; 481 [owned release]; 482 [fromIvar release]; 483 clang_analyzer_eval(owned == fromIvar); // expected-warning{{TRUE}} 484 } 485 486 - (void)testPropertyAccessThenReleaseUnowned { 487 id unowned = [self.unownedProp retain]; 488 [unowned release]; 489 [_unownedProp release]; // FIXME-warning{{not owned}} 490 } 491 492 - (void)testPropertyAccessThenReleaseUnowned2 { 493 id fromIvar = _unownedProp; 494 id unowned = [self.unownedProp retain]; 495 [unowned release]; 496 clang_analyzer_eval(unowned == fromIvar); // expected-warning{{TRUE}} 497 [fromIvar release]; // FIXME-warning{{not owned}} 498 } 499 500 - (void)testPropertyAccessThenReleaseManual { 501 id prop = [self.manualProp retain]; 502 [prop release]; 503 [_manualProp release]; // no-warning 504 } 505 506 - (void)testPropertyAccessThenReleaseManual2 { 507 id fromIvar = _manualProp; 508 id prop = [self.manualProp retain]; 509 [prop release]; 510 clang_analyzer_eval(prop == fromIvar); // expected-warning{{TRUE}} 511 [fromIvar release]; // no-warning 512 } 513 514 - (void)testPropertyAccessThenReleaseCF { 515 CFTypeRef owned = CFRetain(self.cfProp); 516 CFRelease(owned); 517 CFRelease(_cfProp); // no-warning 518 clang_analyzer_eval(owned == _cfProp); // expected-warning{{TRUE}} 519 } 520 521 - (void)testPropertyAccessThenReleaseCF2 { 522 CFTypeRef fromIvar = _cfProp; 523 CFTypeRef owned = CFRetain(self.cfProp); 524 CFRelease(owned); 525 CFRelease(fromIvar); 526 clang_analyzer_eval(owned == fromIvar); // expected-warning{{TRUE}} 527 } 528 529 - (void)testPropertyAccessThenReleaseReadonly { 530 id prop = [self.readonlyProp retain]; 531 [prop release]; 532 [_readonlyProp release]; // no-warning 533 } 534 535 - (void)testPropertyAccessThenReleaseReadonly2 { 536 id fromIvar = _readonlyProp; 537 id prop = [self.readonlyProp retain]; 538 [prop release]; 539 clang_analyzer_eval(prop == fromIvar); // expected-warning{{TRUE}} 540 [fromIvar release]; // no-warning 541 } 542 543 - (void)testPropertyAccessThenReleaseImplicitManual { 544 id prop = [self.implicitManualProp retain]; 545 [prop release]; 546 [_implicitManualProp release]; // no-warning 547 } 548 549 - (void)testPropertyAccessThenReleaseImplicitManual2 { 550 id fromIvar = _implicitManualProp; 551 id prop = [self.implicitManualProp retain]; 552 [prop release]; 553 clang_analyzer_eval(prop == fromIvar); // expected-warning{{TRUE}} 554 [fromIvar release]; // no-warning 555 } 556 557 - (void)testPropertyAccessThenReleaseImplicitSynth { 558 id prop = [self.implicitSynthProp retain]; 559 [prop release]; 560 [_implicitSynthProp release]; // FIXME-warning{{not owned}} 561 } 562 563 - (void)testPropertyAccessThenReleaseImplicitSynth2 { 564 id fromIvar = _implicitSynthProp; 565 id prop = [self.implicitSynthProp retain]; 566 [prop release]; 567 clang_analyzer_eval(prop == fromIvar); // expected-warning{{TRUE}} 568 [fromIvar release]; // FIXME-warning{{not owned}} 569 } 570 571 - (id)getUnownedFromProperty { 572 [_ownedProp retain]; 573 [_ownedProp autorelease]; 574 return _ownedProp; // no-warning 575 } 576 577 - (id)transferUnownedFromProperty { 578 [_ownedProp retain]; 579 [_ownedProp autorelease]; 580 return [_ownedProp autorelease]; // no-warning 581 } 582 583 - (id)transferOwnedFromProperty __attribute__((ns_returns_retained)) { 584 [_ownedProp retain]; 585 [_ownedProp autorelease]; 586 return _ownedProp; // no-warning 587 } 588 589 - (void)testAssignOwned:(id)newValue { 590 _ownedProp = newValue; 591 [_ownedProp release]; // FIXME: no-warning{{not owned}} 592 } 593 594 - (void)testAssignUnowned:(id)newValue { 595 _unownedProp = newValue; 596 [_unownedProp release]; // FIXME: no-warning{{not owned}} 597 } 598 599 - (void)testAssignIvarOnly:(id)newValue { 600 _ivarOnly = newValue; 601 [_ivarOnly release]; // FIXME: no-warning{{not owned}} 602 } 603 604 - (void)testAssignCF:(CFTypeRef)newValue { 605 _cfProp = newValue; 606 CFRelease(_cfProp); // FIXME: no-warning{{not owned}} 607 } 608 609 - (void)testAssignReadonly:(id)newValue { 610 _readonlyProp = newValue; 611 [_readonlyProp release]; // FIXME: no-warning{{not owned}} 612 } 613 614 - (void)testAssignImplicitManual:(id)newValue { 615 _implicitManualProp = newValue; 616 [_implicitManualProp release]; // FIXME: no-warning{{not owned}} 617 } 618 619 - (void)testAssignImplicitSynth:(id)newValue { 620 _implicitSynthProp = newValue; 621 [_implicitSynthProp release]; // FIXME: no-warning{{not owned}} 622 } 623 624 - (void)testAssignOwnedOkay:(id)newValue { 625 _ownedProp = [newValue retain]; 626 [_ownedProp release]; // no-warning 627 } 628 629 - (void)testAssignUnownedOkay:(id)newValue { 630 _unownedProp = [newValue retain]; 631 [_unownedProp release]; // no-warning 632 } 633 634 - (void)testAssignIvarOnlyOkay:(id)newValue { 635 _ivarOnly = [newValue retain]; 636 [_ivarOnly release]; // no-warning 637 } 638 639 - (void)testAssignCFOkay:(CFTypeRef)newValue { 640 _cfProp = CFRetain(newValue); 641 CFRelease(_cfProp); // no-warning 642 } 643 644 - (void)testAssignReadonlyOkay:(id)newValue { 645 _readonlyProp = [newValue retain]; 646 [_readonlyProp release]; // FIXME: no-warning{{not owned}} 647 } 648 649 - (void)testAssignImplicitManualOkay:(id)newValue { 650 _implicitManualProp = [newValue retain]; 651 [_implicitManualProp release]; // FIXME: no-warning{{not owned}} 652 } 653 654 - (void)testAssignImplicitSynthOkay:(id)newValue { 655 _implicitSynthProp = [newValue retain]; 656 [_implicitSynthProp release]; // FIXME: no-warning{{not owned}} 657 } 658 659 // rdar://problem/19862648 660 - (void)establishIvarIsNilDuringLoops { 661 extern id getRandomObject(); 662 663 int i = 4; // Must be at least 4 to trigger the bug. 664 while (--i) { 665 id x = 0; 666 if (getRandomObject()) 667 x = _ivarOnly; 668 if (!x) 669 x = getRandomObject(); 670 [x myMethod]; 671 } 672 } 673 674 // rdar://problem/20335433 675 - (void)retainIvarAndInvalidateSelf { 676 extern void invalidate(id); 677 [_unownedProp retain]; 678 invalidate(self); 679 [_unownedProp release]; // no-warning 680 } 681 682 @end 683 #endif // non-ARC 684 685