1// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-config ipa=dynamic-bifurcate -verify %s 2 3typedef signed char BOOL; 4typedef struct objc_class *Class; 5typedef 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 31void 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; 71typedef 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 92void releaseObj(DelegateTest *c); 93 94// Releases object through callback. 95void 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