reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231
  232
  233
  234
  235
  236
  237
  238
  239
  240
  241
  242
  243
  244
  245
  246
  247
  248
  249
  250
  251
  252
  253
  254
  255
  256
  257
  258
  259
  260
  261
  262
  263
  264
  265
  266
  267
  268
  269
  270
  271
  272
  273
  274
  275
  276
  277
  278
  279
  280
  281
  282
  283
  284
  285
  286
  287
  288
  289
  290
  291
  292
  293
  294
  295
  296
  297
  298
  299
  300
  301
  302
  303
  304
  305
  306
  307
  308
  309
  310
  311
  312
  313
  314
  315
  316
  317
  318
  319
  320
  321
  322
  323
  324
  325
  326
  327
  328
  329
  330
  331
// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -analyzer-output=text -verify %s
// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.ClassRelease,osx.cocoa.RetainCount -analyzer-store=region -analyzer-output=plist-multi-file %s -o %t
// RUN: %normalize_plist <%t | diff -ub %S/Inputs/expected-plists/retain-release-path-notes.m.plist -

/***
This file is for testing the path-sensitive notes for retain/release errors.
Its goal is to have simple branch coverage of any path-based diagnostics,
not to actually check all possible retain/release errors.

This file includes notes that only appear in a ref-counted analysis. 
GC-specific notes should go in retain-release-path-notes-gc.m.
***/

@interface NSObject
+ (id)alloc;
- (id)init;
- (void)dealloc;

- (Class)class;

- (id)retain;
- (void)release;
- (void)autorelease;
@end

@interface Foo : NSObject
- (id)methodWithValue;
@property(retain) id propertyValue;

- (id)objectAtIndexedSubscript:(unsigned)index;
- (id)objectForKeyedSubscript:(id)key;
@end

typedef struct CFType *CFTypeRef;
CFTypeRef CFRetain(CFTypeRef);
void CFRelease(CFTypeRef);
CFTypeRef CFAutorelease(CFTypeRef __attribute__((cf_consumed)));

id NSMakeCollectable(CFTypeRef);
CFTypeRef CFMakeCollectable(CFTypeRef);

CFTypeRef CFCreateSomething();
CFTypeRef CFGetSomething();


void creationViaAlloc () {
  id leaked = [[NSObject alloc] init]; // expected-note{{Method returns an instance of NSObject with a +1 retain count}}
  return; // expected-warning{{leak}} 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}}
}

void creationViaCFCreate () {
  CFTypeRef leaked = CFCreateSomething(); // expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object of type 'CFTypeRef' with a +1 retain count}}
  return; // expected-warning{{leak}} 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}}
}

void acquisitionViaMethod (Foo *foo) {
  id leaked = [foo methodWithValue]; // expected-note{{Method returns an Objective-C object with a +0 retain count}}
  [leaked retain]; // expected-note{{Reference count incremented. The object now has a +1 retain count}}
  [leaked retain]; // expected-note{{Reference count incremented. The object now has a +2 retain count}}
  [leaked release]; // expected-note{{Reference count decremented. The object now has a +1 retain count}}
  return; // expected-warning{{leak}} 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}}
}

void acquisitionViaProperty (Foo *foo) {
  id leaked = foo.propertyValue; // expected-note{{Property returns an Objective-C object with a +0 retain count}}
  [leaked retain]; // expected-note{{Reference count incremented. The object now has a +1 retain count}}
  return; // expected-warning{{leak}} 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}}
}

void acquisitionViaCFFunction () {
  CFTypeRef leaked = CFGetSomething(); // expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object of type 'CFTypeRef' with a +0 retain count}}
  CFRetain(leaked); // expected-note{{Reference count incremented. The object now has a +1 retain count}}
  return; // expected-warning{{leak}} 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}}
}

void explicitDealloc () {
  id object = [[NSObject alloc] init]; // expected-note{{Method returns an instance of NSObject with a +1 retain count}}
  [object dealloc]; // expected-note{{Object released by directly sending the '-dealloc' message}}
  [object class]; // expected-warning{{Reference-counted object is used after it is released}} // expected-note{{Reference-counted object is used after it is released}}
}

void implicitDealloc () {
  id object = [[NSObject alloc] init]; // expected-note{{Method returns an instance of NSObject with a +1 retain count}}
  [object release]; // expected-note{{Object released}}
  [object class]; // expected-warning{{Reference-counted object is used after it is released}} // expected-note{{Reference-counted object is used after it is released}}
}

void overAutorelease () {
  id object = [[NSObject alloc] init]; // expected-note{{Method returns an instance of NSObject with a +1 retain count}}
  [object autorelease]; // expected-note{{Object autoreleased}}
  [object autorelease]; // expected-note{{Object autoreleased}} 
  return; // expected-warning{{Object autoreleased too many times}} expected-note{{Object was autoreleased 2 times but the object has a +1 retain count}} 
}

void autoreleaseUnowned (Foo *foo) {
  id object = foo.propertyValue; // expected-note{{Property returns an Objective-C object with a +0 retain count}}
  [object autorelease]; // expected-note{{Object autoreleased}} 
  return; // expected-warning{{Object autoreleased too many times}} expected-note{{Object was autoreleased but has a +0 retain count}}
}

void makeCollectableIgnored() {
  CFTypeRef leaked = CFCreateSomething(); // expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object of type 'CFTypeRef' with a +1 retain count}}
  CFMakeCollectable(leaked);
  NSMakeCollectable(leaked);
  return; // expected-warning{{leak}} 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}}
}

CFTypeRef CFCopyRuleViolation () {
  CFTypeRef object = CFGetSomething(); // expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object of type 'CFTypeRef' with a +0 retain count}}
  return object; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
}

CFTypeRef CFGetRuleViolation () {
  CFTypeRef object = CFCreateSomething(); // expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object of type 'CFTypeRef' with a +1 retain count}}
  return object; // expected-warning{{leak}} 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}}
}

@implementation Foo (FundamentalMemoryManagementRules)
- (id)copyViolation {
  id result = self.propertyValue; // expected-note{{Property returns an Objective-C object with a +0 retain count}}
  return result; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
}

- (id)copyViolationIndexedSubscript {
  id result = self[0]; // expected-note{{Subscript returns an Objective-C object with a +0 retain count}}
  return result; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
}

- (id)copyViolationKeyedSubscript {
  id result = self[self]; // expected-note{{Subscript returns an Objective-C object with a +0 retain count}}
  return result; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
}

- (id)getViolation {
  id result = [[Foo alloc] init]; // expected-note{{Method returns an instance of Foo with a +1 retain count}}
  return result; // expected-warning{{leak}} 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}}
}

- (id)copyAutorelease {
  id result = [[Foo alloc] init]; // expected-note{{Method returns an instance of Foo with a +1 retain count}}
  [result autorelease]; // expected-note{{Object autoreleased}}
  return result; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
}
@end


typedef unsigned long NSUInteger;

@interface NSValue : NSObject
@end

@interface NSNumber : NSValue
+ (NSNumber *)numberWithInt:(int)i;
@end

@interface NSString : NSObject
+ (NSString *)stringWithUTF8String:(const char *)str;
@end

@interface NSArray : NSObject
+ (NSArray *)arrayWithObjects:(const id [])objects count:(NSUInteger)count;
@end

@interface NSDictionary : NSObject
+ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id /* <NSCopying> */ [])keys count:(NSUInteger)count;
@end


void testNumericLiteral() {
  id result = @1; // expected-note{{NSNumber literal is an object with a +0 retain count}}
  [result release]; // expected-warning{{decrement}} expected-note{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
}

void testBoxedInt(int x) {
  id result = @(x); // expected-note{{NSNumber boxed expression produces an object with a +0 retain count}}
  [result release]; // expected-warning{{decrement}} expected-note{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
}

void testBoxedString(const char *str) {
  id result = @(str); // expected-note{{NSString boxed expression produces an object with a +0 retain count}}
  [result release]; // expected-warning{{decrement}} expected-note{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
}

void testArray(id obj) {
  id result = @[obj]; // expected-note{{NSArray literal is an object with a +0 retain count}}
  [result release]; // expected-warning{{decrement}} expected-note{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
}

void testDictionary(id key, id value) {
  id result = @{key: value}; // expected-note{{NSDictionary literal is an object with a +0 retain count}}
  [result release]; // expected-warning{{decrement}} expected-note{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
}

// Test that we step into the init method when the allocated object is leaked due to early escape within init.

static int Cond;
@interface MyObj : NSObject
-(id)initX;
-(id)initY;
-(id)initZ;
+(void)test;
@end

@implementation MyObj

-(id)initX {
  if (Cond)  // expected-note {{Assuming 'Cond' is not equal to 0}}
             // expected-note@-1{{Taking true branch}}
    return 0;
  self = [super init];
  return self;
}

-(id)initY {
  self = [super init]; //expected-note {{Method returns an instance of MyObj with a +1 retain count}}
  return self;
}

-(id)initZ {
  self = [super init];
  return self;
}

+(void)test {
  // initX is inlined since we explicitly mark it as interesting
  id x = [[MyObj alloc] initX]; // expected-warning {{Potential leak of an object}}
                                // expected-note@-1 {{Method returns an instance of MyObj with a +1 retain count}}
                                // expected-note@-2 {{Calling 'initX'}}
                                // expected-note@-3 {{Returning from 'initX'}}
                                // expected-note@-4 {{Object leaked: allocated object of type 'MyObj *' is not referenced later in this execution path and has a retain count of +1}}
  // initI is inlined because the allocation happens within initY
  id y = [[MyObj alloc] initY];
                                // expected-note@-1 {{Calling 'initY'}}
                                // expected-note@-2 {{Returning from 'initY'}}

  // initZ is not inlined
  id z = [[MyObj alloc] initZ]; // expected-warning {{Potential leak of an object}}
                                // expected-note@-1 {{Object leaked: object allocated and stored into 'y' is not referenced later in this execution path and has a retain count of +1}}

  [x release];
  [z release];
}
@end


void CFOverAutorelease() {
  CFTypeRef object = CFCreateSomething(); // expected-note{{Call to function 'CFCreateSomething' returns a Core Foundation object of type 'CFTypeRef' with a +1 retain count}}
  CFAutorelease(object); // expected-note{{Object autoreleased}}
  CFAutorelease(object); // expected-note{{Object autoreleased}}
  return; // expected-warning{{Object autoreleased too many times}} expected-note{{Object was autoreleased 2 times but the object has a +1 retain count}}
}

void CFAutoreleaseUnowned() {
  CFTypeRef object = CFGetSomething(); // expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object of type 'CFTypeRef' with a +0 retain count}}
  CFAutorelease(object); // expected-note{{Object autoreleased}}
  return; // expected-warning{{Object autoreleased too many times}} expected-note{{Object was autoreleased but has a +0 retain count}}
}

void CFAutoreleaseUnownedMixed() {
  CFTypeRef object = CFGetSomething(); // expected-note{{Call to function 'CFGetSomething' returns a Core Foundation object of type 'CFTypeRef' with a +0 retain count}}
  CFAutorelease(object); // expected-note{{Object autoreleased}}
  [(id)object autorelease]; // expected-note{{Object autoreleased}}
  return; // expected-warning{{Object autoreleased too many times}} expected-note{{Object was autoreleased 2 times but the object has a +0 retain count}}
}

@interface PropertiesAndIvars : NSObject
@property (strong) id ownedProp;
@property (unsafe_unretained) id unownedProp;
@property (nonatomic, strong) id manualProp;
@end

@interface NSObject (PropertiesAndIvarsHelper)
- (void)myMethod;
@end

@implementation PropertiesAndIvars {
  id _ivarOnly;
}

- (id)manualProp {
  return _manualProp;
}

- (void)testOverreleaseUnownedIvar {
  [_unownedProp retain]; // FIXME-note {{Object loaded from instance variable}}
  // FIXME-note@-1 {{Reference count incremented. The object now has a +1 retain count}}
  [_unownedProp release]; // FIXME-note {{Reference count decremented}}
  [_unownedProp release]; // FIXME-note {{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
  // FIXME-warning@-1 {{not owned at this point by the caller}}
}

- (void)testOverreleaseOwnedIvarUse {
  [_ownedProp retain]; // FIXME-note {{Object loaded from instance variable}}
  // FIXME-note@-1 {{Reference count incremented. The object now has a +1 retain count}}
  [_ownedProp release]; // FIXME-note {{Reference count decremented}}
  [_ownedProp release]; // FIXME-note {{Strong instance variable relinquished. Object released}}
  [_ownedProp myMethod]; // FIXME-note {{Reference-counted object is used after it is released}}
  // FIXME-warning@-1 {{used after it is released}}
}

- (void)testOverreleaseIvarOnlyUse {
  [_ivarOnly retain]; // FIXME-note {{Object loaded from instance variable}}
  // FIXME-note@-1 {{Reference count incremented. The object now has a +1 retain count}}
  [_ivarOnly release]; // FIXME-note {{Reference count decremented}}
  [_ivarOnly release]; // FIXME-note {{Strong instance variable relinquished. Object released}}
  [_ivarOnly myMethod]; // FIXME-note {{Reference-counted object is used after it is released}}
  // FIXME-warning@-1 {{used after it is released}}
}

- (void)testOverreleaseOwnedIvarAutorelease {
  [_ownedProp retain]; // FIXME-note {{Object loaded from instance variable}}
  // FIXME-note@-1 {{Reference count incremented. The object now has a +1 retain count}}
  [_ownedProp release]; // FIXME-note {{Reference count decremented}}
  [_ownedProp autorelease]; // FIXME-note {{Object autoreleased}}
  [_ownedProp autorelease]; // FIXME-note {{Object autoreleased}}
  // FIXME-note@+1 {{Object was autoreleased 2 times but the object has a +0 retain count}}
} // FIXME-warning{{Object autoreleased too many times}}

- (void)testOverreleaseIvarOnlyAutorelease {
  [_ivarOnly retain]; // FIXME-note {{Object loaded from instance variable}}
  // FIXME-note@-1 {{Reference count incremented. The object now has a +1 retain count}}
  [_ivarOnly release]; // FIXME-note {{Reference count decremented}}
  [_ivarOnly autorelease]; // FIXME-note {{Object autoreleased}}
  [_ivarOnly autorelease]; // FIXME-note {{Object autoreleased}}
  // FIXME-note@+1 {{Object was autoreleased 2 times but the object has a +0 retain count}}
} // FIXME-warning{{Object autoreleased too many times}}

@end