properties.m revision 3ea9e33ea25e0c2b12db56418ba3f994eb662c04
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
4void clang_analyzer_eval(int);
5
6typedef const void * CFTypeRef;
7extern CFTypeRef CFRetain(CFTypeRef cf);
8void CFRelease(CFTypeRef cf);
9
10typedef signed char BOOL;
11typedef unsigned int NSUInteger;
12typedef 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
120NSNumber* 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)
144void 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
193extern void doSomethingWithPerson(Person *p);
194extern void doSomethingWithName(NSString *name);
195
196void 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
205void 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)
215void 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
275void 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
285void 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
300void 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
310void testConsistencyIntAuto2(IntWrapperAuto *w) {
311  if (w.value != 42)
312    return;
313
314  clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}}
315}
316
317
318typedef 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
330void 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.
347void 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]; // expected-warning{{used after it is released}}
380}
381
382- (void)testOverreleaseUnownedIvar {
383  [_unownedProp retain];
384  [_unownedProp release];
385  [_unownedProp release]; // expected-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]; // expected-warning{{used after it is released}}
393}
394
395- (void)testOverreleaseReadonlyIvar {
396  [_readonlyProp retain];
397  [_readonlyProp release];
398  [_readonlyProp release];
399  [_readonlyProp release]; // expected-warning{{used after it is released}}
400}
401
402- (void)testOverreleaseImplicitManualIvar {
403  [_implicitManualProp retain];
404  [_implicitManualProp release];
405  [_implicitManualProp release];
406  [_implicitManualProp release]; // expected-warning{{used after it is released}}
407}
408
409- (void)testOverreleaseImplicitSynthIvar {
410  [_implicitSynthProp retain];
411  [_implicitSynthProp release];
412  [_implicitSynthProp release]; // expected-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); // expected-warning{{used after it is released}}
420}
421
422- (void)testOverreleaseOwnedIvarUse {
423  [_ownedProp retain];
424  [_ownedProp release];
425  [_ownedProp release];
426  [_ownedProp myMethod]; // expected-warning{{used after it is released}}
427}
428
429- (void)testOverreleaseIvarOnlyUse {
430  [_ivarOnly retain];
431  [_ivarOnly release];
432  [_ivarOnly release];
433  [_ivarOnly myMethod]; // expected-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); // expected-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} // expected-warning{{Object autoreleased too many times}}
463
464- (void)testOverreleaseIvarOnlyAutorelease {
465  [_ivarOnly retain];
466  [_ivarOnly release];
467  [_ivarOnly autorelease];
468  [_ivarOnly autorelease];
469} // expected-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]; // expected-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]; // expected-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]; // expected-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]; // expected-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@end
675#endif // non-ARC
676
677