1 // RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-config ipa=dynamic-bifurcate -verify %s 2 3 typedef signed char BOOL; 4 typedef struct objc_class *Class; 5 typedef struct objc_object { 6 Class isa; 7 } *id; 8 @protocol NSObject - (BOOL)isEqual:(id)object; @end 9 @interface NSObject <NSObject> {} 10 +(id)alloc; 11 +(id)new; 12 - (oneway void)release; 13 -(id)init; 14 -(id)autorelease; 15 -(id)copy; 16 - (Class)class; 17 -(id)retain; 18 - (oneway void)release; 19 @end 20 21 @interface SelfStaysLive : NSObject 22 - (id)init; 23 @end 24 25 @implementation SelfStaysLive 26 - (id)init { 27 return [super init]; 28 } 29 @end 30 31 void selfStaysLive() { 32 SelfStaysLive *foo = [[SelfStaysLive alloc] init]; 33 [foo release]; 34 } 35 36 // Test that retain release checker warns on leaks and use-after-frees when 37 // self init is not enabled. 38 // radar://12115830 39 @interface ParentOfCell : NSObject 40 - (id)initWithInt: (int)inInt; 41 @end 42 @interface Cell : ParentOfCell{ 43 int x; 44 } 45 - (id)initWithInt: (int)inInt; 46 + (void)testOverRelease; 47 + (void)testLeak; 48 @property int x; 49 @end 50 @implementation Cell 51 @synthesize x; 52 - (id) initWithInt: (int)inInt { 53 [super initWithInt: inInt]; 54 self.x = inInt; // no-warning 55 return self; // Self Init checker would produce a warning here. 56 } 57 + (void) testOverRelease { 58 Cell *sharedCell3 = [[Cell alloc] initWithInt: 3]; 59 [sharedCell3 release]; 60 [sharedCell3 release]; // expected-warning {{Reference-counted object is used after it is released}} 61 } 62 + (void) testLeak { 63 Cell *sharedCell4 = [[Cell alloc] initWithInt: 3]; // expected-warning {{leak}} 64 } 65 @end 66 67 // We should stop tracking some objects even when we inline the call. 68 // Specialically, the objects passed into calls with delegate and callback 69 // parameters. 70 @class DelegateTest; 71 typedef void (*ReleaseCallbackTy) (DelegateTest *c); 72 73 @interface Delegate : NSObject 74 @end 75 76 @interface DelegateTest : NSObject { 77 Delegate *myDel; 78 } 79 // Object initialized with a delagate which could potentially release it. 80 - (id)initWithDelegate: (id) d; 81 82 - (void) setDelegate: (id) d; 83 84 // Releases object through callback. 85 + (void)updateObject:(DelegateTest*)obj WithCallback:(ReleaseCallbackTy)rc; 86 87 + (void)test: (Delegate *)d; 88 89 @property (assign) Delegate* myDel; 90 @end 91 92 void releaseObj(DelegateTest *c); 93 94 // Releases object through callback. 95 void updateObject(DelegateTest *c, ReleaseCallbackTy rel) { 96 rel(c); 97 } 98 99 @implementation DelegateTest 100 @synthesize myDel; 101 102 - (id) initWithDelegate: (id) d { 103 if ((self = [super init])) 104 myDel = d; 105 return self; 106 } 107 108 - (void) setDelegate: (id) d { 109 myDel = d; 110 } 111 112 + (void)updateObject:(DelegateTest*)obj WithCallback:(ReleaseCallbackTy)rc { 113 rc(obj); 114 } 115 116 + (void) test: (Delegate *)d { 117 DelegateTest *obj1 = [[DelegateTest alloc] initWithDelegate: d]; // no-warning 118 DelegateTest *obj2 = [[DelegateTest alloc] init]; // no-warning 119 DelegateTest *obj3 = [[DelegateTest alloc] init]; // no-warning 120 updateObject(obj2, releaseObj); 121 [DelegateTest updateObject: obj3 122 WithCallback: releaseObj]; 123 DelegateTest *obj4 = [[DelegateTest alloc] init]; // no-warning 124 [obj4 setDelegate: d]; 125 } 126 @end 127 128