Home | History | Annotate | Download | only in Analysis
      1 // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -analyzer-output=text -verify %s
      2 
      3 // This actually still works after the pseudo-object refactor, it just
      4 // uses messages that say 'method' instead of 'property'.  Ted wanted
      5 // this xfailed and filed as a bug.  rdar://problem/10402993
      6 
      7 /***
      8 This file is for testing the path-sensitive notes for retain/release errors.
      9 Its goal is to have simple branch coverage of any path-based diagnostics,
     10 not to actually check all possible retain/release errors.
     11 
     12 This file includes notes that only appear in a ref-counted analysis. 
     13 GC-specific notes should go in retain-release-path-notes-gc.m.
     14 ***/
     15 
     16 @interface NSObject
     17 + (id)alloc;
     18 - (id)init;
     19 - (void)dealloc;
     20 
     21 - (Class)class;
     22 
     23 - (id)retain;
     24 - (void)release;
     25 - (void)autorelease;
     26 @end
     27 
     28 @interface Foo : NSObject
     29 - (id)methodWithValue;
     30 @property(retain) id propertyValue;
     31 @end
     32 
     33 typedef struct CFType *CFTypeRef;
     34 CFTypeRef CFRetain(CFTypeRef);
     35 void CFRelease(CFTypeRef);
     36 
     37 id NSMakeCollectable(CFTypeRef);
     38 CFTypeRef CFMakeCollectable(CFTypeRef);
     39 
     40 CFTypeRef CFCreateSomething();
     41 CFTypeRef CFGetSomething();
     42 
     43 
     44 void creationViaAlloc () {
     45   id leaked = [[NSObject alloc] init]; // expected-warning{{leak}} expected-note{{Method returns an Objective-C object with a +1 retain count}}
     46   return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
     47 }
     48 
     49 void creationViaCFCreate () {
     50   CFTypeRef leaked = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}}
     51   return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
     52 }
     53 
     54 void acquisitionViaMethod (Foo *foo) {
     55   id leaked = [foo methodWithValue]; // expected-warning{{leak}} expected-note{{Method returns an Objective-C object with a +0 retain count}}
     56   [leaked retain]; // expected-note{{Reference count incremented. The object now has a +1 retain count}}
     57   [leaked retain]; // expected-note{{Reference count incremented. The object now has a +2 retain count}}
     58   [leaked release]; // expected-note{{Reference count decremented. The object now has a +1 retain count}}
     59   return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
     60 }
     61 
     62 void acquisitionViaProperty (Foo *foo) {
     63   id leaked = foo.propertyValue; // expected-warning{{leak}} expected-note{{Property returns an Objective-C object with a +0 retain count}}
     64   [leaked retain]; // expected-note{{Reference count incremented. The object now has a +1 retain count}}
     65   return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
     66 }
     67 
     68 void acquisitionViaCFFunction () {
     69   CFTypeRef leaked = CFGetSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain count}}
     70   CFRetain(leaked); // expected-note{{Reference count incremented. The object now has a +1 retain count}}
     71   return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
     72 }
     73 
     74 void explicitDealloc () {
     75   id object = [[NSObject alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}}
     76   [object dealloc]; // expected-note{{Object released by directly sending the '-dealloc' message}}
     77   [object class]; // expected-warning{{Reference-counted object is used after it is released}} // expected-note{{Reference-counted object is used after it is released}}
     78 }
     79 
     80 void implicitDealloc () {
     81   id object = [[NSObject alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}}
     82   [object release]; // expected-note{{Object released}}
     83   [object class]; // expected-warning{{Reference-counted object is used after it is released}} // expected-note{{Reference-counted object is used after it is released}}
     84 }
     85 
     86 void overAutorelease () {
     87   id object = [[NSObject alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}}
     88   [object autorelease]; // expected-note{{Object sent -autorelease message}}
     89   [object autorelease]; // expected-note{{Object sent -autorelease message}} 
     90   return; // expected-warning{{Object sent -autorelease too many times}} expected-note{{Object over-autoreleased: object was sent -autorelease 2 times but the object has a +1 retain count}} 
     91 }
     92 
     93 void autoreleaseUnowned (Foo *foo) {
     94   id object = foo.propertyValue; // expected-note{{Property returns an Objective-C object with a +0 retain count}}
     95   [object autorelease]; // expected-note{{Object sent -autorelease message}} 
     96   return; // expected-warning{{Object sent -autorelease too many times}} expected-note{{Object over-autoreleased: object was sent -autorelease but the object has a +0 retain count}}
     97 }
     98 
     99 void makeCollectableIgnored () {
    100   CFTypeRef leaked = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}}
    101   CFMakeCollectable(leaked); // expected-note{{When GC is not enabled a call to 'CFMakeCollectable' has no effect on its argument}}
    102   NSMakeCollectable(leaked); // expected-note{{When GC is not enabled a call to 'NSMakeCollectable' has no effect on its argument}}
    103   return; // expected-note{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
    104 }
    105 
    106 CFTypeRef CFCopyRuleViolation () {
    107   CFTypeRef object = CFGetSomething(); // expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object with a +0 retain count}}
    108   return object; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object returned to caller with a +0 retain count}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
    109 }
    110 
    111 CFTypeRef CFGetRuleViolation () {
    112   CFTypeRef object = CFCreateSomething(); // expected-warning{{leak}} expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object with a +1 retain count}}
    113   return object; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'object' is returned from a function whose name ('CFGetRuleViolation') does not contain 'Copy' or 'Create'.  This violates the naming convention rules given in the Memory Management Guide for Core Foundation}}
    114 }
    115 
    116 @implementation Foo (FundamentalMemoryManagementRules)
    117 - (id)copyViolation {
    118   id result = self.propertyValue; // expected-note{{Property returns an Objective-C object with a +0 retain count}}
    119   return result; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object returned to caller with a +0 retain count}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
    120 }
    121 
    122 - (id)getViolation {
    123   id result = [[Foo alloc] init]; // expected-warning{{leak}} expected-note{{Method returns an Objective-C object with a +1 retain count}}
    124   return result; // expected-note{{Object returned to caller as an owning reference (single retain count transferred to caller)}} expected-note{{Object leaked: object allocated and stored into 'result' is returned from a method whose name ('getViolation') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'.  This violates the naming convention rules given in the Memory Management Guide for Cocoa}}
    125 }
    126 
    127 - (id)copyAutorelease {
    128   id result = [[Foo alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}}
    129   [result autorelease]; // expected-note{{Object sent -autorelease message}}
    130   return result; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object returned to caller with a +0 retain count}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
    131 }
    132 @end
    133