2014-01-11 04:06:06 +08:00
|
|
|
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,debug.ExprInspection -analyzer-store=region -verify -Wno-objc-root-class %s
|
2014-01-23 11:59:10 +08:00
|
|
|
// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,debug.ExprInspection -analyzer-store=region -verify -Wno-objc-root-class -fobjc-arc %s
|
2014-01-11 04:06:06 +08:00
|
|
|
|
|
|
|
void clang_analyzer_eval(int);
|
2011-01-25 08:04:03 +08:00
|
|
|
|
2015-03-07 13:47:24 +08:00
|
|
|
typedef const void * CFTypeRef;
|
|
|
|
extern CFTypeRef CFRetain(CFTypeRef cf);
|
|
|
|
void CFRelease(CFTypeRef cf);
|
|
|
|
|
2011-01-25 08:04:03 +08:00
|
|
|
typedef signed char BOOL;
|
|
|
|
typedef unsigned int NSUInteger;
|
|
|
|
typedef struct _NSZone NSZone;
|
|
|
|
@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
|
|
|
|
@protocol NSObject - (BOOL)isEqual:(id)object; @end
|
|
|
|
@protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end
|
|
|
|
@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end
|
|
|
|
@protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; @end
|
|
|
|
@interface NSObject <NSObject> {}
|
|
|
|
+(id)alloc;
|
|
|
|
-(id)init;
|
|
|
|
-(id)autorelease;
|
|
|
|
-(id)copy;
|
|
|
|
-(id)retain;
|
2014-01-11 04:06:06 +08:00
|
|
|
-(oneway void)release;
|
2011-01-25 08:04:03 +08:00
|
|
|
@end
|
|
|
|
@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>
|
|
|
|
- (NSUInteger)length;
|
|
|
|
-(id)initWithFormat:(NSString *)f,...;
|
|
|
|
-(BOOL)isEqualToString:(NSString *)s;
|
|
|
|
+ (id)string;
|
|
|
|
@end
|
|
|
|
@interface NSNumber : NSObject {}
|
|
|
|
+(id)alloc;
|
|
|
|
-(id)initWithInteger:(int)i;
|
|
|
|
@end
|
|
|
|
|
|
|
|
// rdar://6946338
|
|
|
|
|
|
|
|
@interface Test1 : NSObject {
|
|
|
|
NSString *text;
|
|
|
|
}
|
|
|
|
-(id)myMethod;
|
|
|
|
@property (nonatomic, assign) NSString *text;
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
2014-01-23 11:59:10 +08:00
|
|
|
#if !__has_feature(objc_arc)
|
|
|
|
|
2011-01-25 08:04:03 +08:00
|
|
|
@implementation Test1
|
|
|
|
|
|
|
|
@synthesize text;
|
|
|
|
|
|
|
|
-(id)myMethod {
|
|
|
|
Test1 *cell = [[[Test1 alloc] init] autorelease];
|
|
|
|
|
|
|
|
NSString *string1 = [[NSString alloc] initWithFormat:@"test %f", 0.0]; // expected-warning {{Potential leak}}
|
|
|
|
cell.text = string1;
|
|
|
|
|
|
|
|
return cell;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
// rdar://8824416
|
|
|
|
|
|
|
|
@interface MyNumber : NSObject
|
|
|
|
{
|
|
|
|
NSNumber* _myNumber;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id)initWithNumber:(NSNumber *)number;
|
|
|
|
|
|
|
|
@property (nonatomic, readonly) NSNumber* myNumber;
|
|
|
|
@property (nonatomic, readonly) NSNumber* newMyNumber;
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation MyNumber
|
|
|
|
@synthesize myNumber=_myNumber;
|
|
|
|
|
|
|
|
- (id)initWithNumber:(NSNumber *)number
|
|
|
|
{
|
|
|
|
self = [super init];
|
|
|
|
|
|
|
|
if ( self )
|
|
|
|
{
|
|
|
|
_myNumber = [number copy];
|
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSNumber*)newMyNumber
|
|
|
|
{
|
|
|
|
if ( _myNumber )
|
|
|
|
return [_myNumber retain];
|
|
|
|
|
|
|
|
return [[NSNumber alloc] initWithInteger:1];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id)valueForUndefinedKey:(NSString*)key
|
|
|
|
{
|
|
|
|
id value = 0;
|
|
|
|
|
|
|
|
if ([key isEqualToString:@"MyIvarNumberAsPropertyOverReleased"])
|
|
|
|
value = self.myNumber; // _myNumber will be over released, since the value returned from self.myNumber is not retained.
|
|
|
|
else if ([key isEqualToString:@"MyIvarNumberAsPropertyOk"])
|
|
|
|
value = [self.myNumber retain]; // this line fixes the over release
|
|
|
|
else if ([key isEqualToString:@"MyIvarNumberAsNewMyNumber"])
|
|
|
|
value = self.newMyNumber; // this one is ok, since value is returned retained
|
|
|
|
else
|
|
|
|
value = [[NSNumber alloc] initWithInteger:0];
|
|
|
|
|
2013-04-23 09:42:25 +08:00
|
|
|
return [value autorelease]; // expected-warning {{Object autoreleased too many times}}
|
2011-01-25 08:04:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
NSNumber* numberFromMyNumberProperty(MyNumber* aMyNumber)
|
|
|
|
{
|
|
|
|
NSNumber* result = aMyNumber.myNumber;
|
|
|
|
|
2013-04-23 09:42:25 +08:00
|
|
|
return [result autorelease]; // expected-warning {{Object autoreleased too many times}}
|
2011-01-25 08:04:03 +08:00
|
|
|
}
|
|
|
|
|
2014-01-23 11:59:10 +08:00
|
|
|
#endif
|
|
|
|
|
2011-01-25 08:04:03 +08:00
|
|
|
|
|
|
|
// rdar://6611873
|
|
|
|
|
|
|
|
@interface Person : NSObject {
|
|
|
|
NSString *_name;
|
|
|
|
}
|
|
|
|
@property (retain) NSString * name;
|
2014-01-23 11:59:10 +08:00
|
|
|
@property (assign) id friend;
|
2011-01-25 08:04:03 +08:00
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation Person
|
|
|
|
@synthesize name = _name;
|
|
|
|
@end
|
|
|
|
|
2014-01-23 11:59:10 +08:00
|
|
|
#if !__has_feature(objc_arc)
|
2011-01-25 08:04:03 +08:00
|
|
|
void rdar6611873() {
|
|
|
|
Person *p = [[[Person alloc] init] autorelease];
|
|
|
|
|
|
|
|
p.name = [[NSString string] retain]; // expected-warning {{leak}}
|
|
|
|
p.name = [[NSString alloc] init]; // expected-warning {{leak}}
|
2014-01-23 11:59:10 +08:00
|
|
|
|
|
|
|
p.friend = [[Person alloc] init]; // expected-warning {{leak}}
|
2011-01-25 08:04:03 +08:00
|
|
|
}
|
2014-01-23 11:59:10 +08:00
|
|
|
#endif
|
2011-01-28 00:17:11 +08:00
|
|
|
|
|
|
|
@interface SubPerson : Person
|
|
|
|
-(NSString *)foo;
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation SubPerson
|
|
|
|
-(NSString *)foo {
|
|
|
|
return super.name;
|
|
|
|
}
|
|
|
|
@end
|
2012-02-19 04:53:30 +08:00
|
|
|
|
2014-01-23 11:59:10 +08:00
|
|
|
|
|
|
|
#if !__has_feature(objc_arc)
|
2012-02-19 04:53:30 +08:00
|
|
|
// <rdar://problem/9241180> Static analyzer doesn't detect uninitialized variable issues for property accesses
|
|
|
|
@interface RDar9241180
|
|
|
|
@property (readwrite,assign) id x;
|
|
|
|
-(id)testAnalyzer1:(int) y;
|
|
|
|
-(void)testAnalyzer2;
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation RDar9241180
|
|
|
|
@synthesize x;
|
|
|
|
-(id)testAnalyzer1:(int)y {
|
|
|
|
RDar9241180 *o;
|
|
|
|
if (y && o.x) // expected-warning {{Property access on an uninitialized object pointer}}
|
|
|
|
return o;
|
|
|
|
return o; // expected-warning {{Undefined or garbage value returned to caller}}
|
|
|
|
}
|
|
|
|
-(void)testAnalyzer2 {
|
|
|
|
id y;
|
|
|
|
self.x = y; // expected-warning {{Argument for property setter is an uninitialized value}}
|
|
|
|
}
|
|
|
|
@end
|
2014-01-23 11:59:10 +08:00
|
|
|
#endif
|
2012-02-19 04:53:30 +08:00
|
|
|
|
|
|
|
|
2014-01-11 04:06:06 +08:00
|
|
|
//------
|
|
|
|
// Property accessor synthesis
|
|
|
|
//------
|
|
|
|
|
[analyzer] Don't track retain counts of objects directly accessed through ivars.
A refinement of r198953 to handle cases where an object is accessed both through
a property getter and through direct ivar access. An object accessed through a
property should always be treated as +0, i.e. not owned by the caller. However,
an object accessed through an ivar may be at +0 or at +1, depending on whether
the ivar is a strong reference. Outside of ARC, we don't have that information,
so we just don't track objects accessed through ivars.
With this change, accessing an ivar directly will deliberately override the +0
provided by a getter, but only if the +0 hasn't participated in other retain
counting yet. That isn't perfect, but it's already unusual for people to be
mixing property access with direct ivar access. (The primary use case for this
is in setters, init methods, and -dealloc.)
Thanks to Ted for spotting a few mistakes in private review.
<rdar://problem/16333368>
llvm-svn: 204730
2014-03-26 01:10:58 +08:00
|
|
|
extern void doSomethingWithPerson(Person *p);
|
|
|
|
extern void doSomethingWithName(NSString *name);
|
|
|
|
|
2014-01-23 11:59:10 +08:00
|
|
|
void testConsistencyRetain(Person *p) {
|
2014-01-11 04:06:06 +08:00
|
|
|
clang_analyzer_eval(p.name == p.name); // expected-warning{{TRUE}}
|
|
|
|
|
|
|
|
id origName = p.name;
|
|
|
|
clang_analyzer_eval(p.name == origName); // expected-warning{{TRUE}}
|
|
|
|
doSomethingWithPerson(p);
|
|
|
|
clang_analyzer_eval(p.name == origName); // expected-warning{{UNKNOWN}}
|
|
|
|
}
|
|
|
|
|
2014-01-23 11:59:10 +08:00
|
|
|
void testConsistencyAssign(Person *p) {
|
|
|
|
clang_analyzer_eval(p.friend == p.friend); // expected-warning{{TRUE}}
|
|
|
|
|
|
|
|
id origFriend = p.friend;
|
|
|
|
clang_analyzer_eval(p.friend == origFriend); // expected-warning{{TRUE}}
|
|
|
|
doSomethingWithPerson(p);
|
|
|
|
clang_analyzer_eval(p.friend == origFriend); // expected-warning{{UNKNOWN}}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if !__has_feature(objc_arc)
|
|
|
|
void testOverrelease(Person *p, int coin) {
|
[analyzer] Don't track retain counts of objects directly accessed through ivars.
A refinement of r198953 to handle cases where an object is accessed both through
a property getter and through direct ivar access. An object accessed through a
property should always be treated as +0, i.e. not owned by the caller. However,
an object accessed through an ivar may be at +0 or at +1, depending on whether
the ivar is a strong reference. Outside of ARC, we don't have that information,
so we just don't track objects accessed through ivars.
With this change, accessing an ivar directly will deliberately override the +0
provided by a getter, but only if the +0 hasn't participated in other retain
counting yet. That isn't perfect, but it's already unusual for people to be
mixing property access with direct ivar access. (The primary use case for this
is in setters, init methods, and -dealloc.)
Thanks to Ted for spotting a few mistakes in private review.
<rdar://problem/16333368>
llvm-svn: 204730
2014-03-26 01:10:58 +08:00
|
|
|
switch (coin) {
|
|
|
|
case 0:
|
2014-01-23 11:59:10 +08:00
|
|
|
[p.name release]; // expected-warning{{not owned}}
|
[analyzer] Don't track retain counts of objects directly accessed through ivars.
A refinement of r198953 to handle cases where an object is accessed both through
a property getter and through direct ivar access. An object accessed through a
property should always be treated as +0, i.e. not owned by the caller. However,
an object accessed through an ivar may be at +0 or at +1, depending on whether
the ivar is a strong reference. Outside of ARC, we don't have that information,
so we just don't track objects accessed through ivars.
With this change, accessing an ivar directly will deliberately override the +0
provided by a getter, but only if the +0 hasn't participated in other retain
counting yet. That isn't perfect, but it's already unusual for people to be
mixing property access with direct ivar access. (The primary use case for this
is in setters, init methods, and -dealloc.)
Thanks to Ted for spotting a few mistakes in private review.
<rdar://problem/16333368>
llvm-svn: 204730
2014-03-26 01:10:58 +08:00
|
|
|
break;
|
|
|
|
case 1:
|
2014-01-23 11:59:10 +08:00
|
|
|
[p.friend release]; // expected-warning{{not owned}}
|
[analyzer] Don't track retain counts of objects directly accessed through ivars.
A refinement of r198953 to handle cases where an object is accessed both through
a property getter and through direct ivar access. An object accessed through a
property should always be treated as +0, i.e. not owned by the caller. However,
an object accessed through an ivar may be at +0 or at +1, depending on whether
the ivar is a strong reference. Outside of ARC, we don't have that information,
so we just don't track objects accessed through ivars.
With this change, accessing an ivar directly will deliberately override the +0
provided by a getter, but only if the +0 hasn't participated in other retain
counting yet. That isn't perfect, but it's already unusual for people to be
mixing property access with direct ivar access. (The primary use case for this
is in setters, init methods, and -dealloc.)
Thanks to Ted for spotting a few mistakes in private review.
<rdar://problem/16333368>
llvm-svn: 204730
2014-03-26 01:10:58 +08:00
|
|
|
break;
|
|
|
|
case 2: {
|
|
|
|
id friend = p.friend;
|
|
|
|
doSomethingWithPerson(p);
|
|
|
|
[friend release]; // expected-warning{{not owned}}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// <rdar://problem/16333368>
|
|
|
|
@implementation Person (Rdar16333368)
|
|
|
|
|
|
|
|
- (void)testDeliberateRelease:(Person *)other {
|
|
|
|
doSomethingWithName(self.name);
|
|
|
|
[_name release]; // no-warning
|
|
|
|
self->_name = 0;
|
|
|
|
|
|
|
|
doSomethingWithName(other->_name);
|
[analyzer] RetainCountChecker: be forgiving when ivars are accessed directly.
A refinement of r204730, itself a refinement of r198953, to better handle
cases where an object is accessed both through a property getter and
through direct ivar access. An object accessed through a property should
always be treated as +0, i.e. not owned by the caller. However, an object
accessed through an ivar may be at +0 or at +1, depending on whether the
ivar is a strong reference. Outside of ARC, we don't always have that
information.
The previous attempt would clear out the +0 provided by a getter, but only
if that +0 hadn't already participated in other retain counting operations.
(That is, "self.foo" is okay, but "[[self.foo retain] autorelease]" is
problematic.) This turned out to not be good enough when our synthesized
getters get involved.
This commit drops the notion of "overridable" reference counting and instead
just tracks whether a value ever came from a (strong) ivar. If it has, we
allow one more release than we otherwise would. This has the added benefit
of being able to catch /some/ overreleases of instance variables, though
it's not likely to come up in practice.
We do still get some false negatives because we currently throw away
refcount state upon assigning a value into an ivar. We should probably
improve on that in the future, especially once we synthesize setters as
well as getters.
rdar://problem/18075108
llvm-svn: 228174
2015-02-05 03:24:52 +08:00
|
|
|
[other.name release]; // no-warning
|
2014-01-11 04:06:06 +08:00
|
|
|
}
|
[analyzer] Don't track retain counts of objects directly accessed through ivars.
A refinement of r198953 to handle cases where an object is accessed both through
a property getter and through direct ivar access. An object accessed through a
property should always be treated as +0, i.e. not owned by the caller. However,
an object accessed through an ivar may be at +0 or at +1, depending on whether
the ivar is a strong reference. Outside of ARC, we don't have that information,
so we just don't track objects accessed through ivars.
With this change, accessing an ivar directly will deliberately override the +0
provided by a getter, but only if the +0 hasn't participated in other retain
counting yet. That isn't perfect, but it's already unusual for people to be
mixing property access with direct ivar access. (The primary use case for this
is in setters, init methods, and -dealloc.)
Thanks to Ted for spotting a few mistakes in private review.
<rdar://problem/16333368>
llvm-svn: 204730
2014-03-26 01:10:58 +08:00
|
|
|
|
|
|
|
- (void)deliberateReleaseFalseNegative {
|
|
|
|
// This is arguably a false negative because the result of p.friend shouldn't
|
|
|
|
// be released, even though we are manipulating the ivar in between the two
|
|
|
|
// actions.
|
|
|
|
id name = self.name;
|
|
|
|
_name = 0;
|
|
|
|
[name release];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)testRetainAndRelease {
|
|
|
|
[self.name retain];
|
|
|
|
[self.name release];
|
|
|
|
[self.name release]; // expected-warning{{not owned}}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)testRetainAndReleaseIVar {
|
|
|
|
[self.name retain];
|
|
|
|
[_name release];
|
[analyzer] RetainCountChecker: be forgiving when ivars are accessed directly.
A refinement of r204730, itself a refinement of r198953, to better handle
cases where an object is accessed both through a property getter and
through direct ivar access. An object accessed through a property should
always be treated as +0, i.e. not owned by the caller. However, an object
accessed through an ivar may be at +0 or at +1, depending on whether the
ivar is a strong reference. Outside of ARC, we don't always have that
information.
The previous attempt would clear out the +0 provided by a getter, but only
if that +0 hadn't already participated in other retain counting operations.
(That is, "self.foo" is okay, but "[[self.foo retain] autorelease]" is
problematic.) This turned out to not be good enough when our synthesized
getters get involved.
This commit drops the notion of "overridable" reference counting and instead
just tracks whether a value ever came from a (strong) ivar. If it has, we
allow one more release than we otherwise would. This has the added benefit
of being able to catch /some/ overreleases of instance variables, though
it's not likely to come up in practice.
We do still get some false negatives because we currently throw away
refcount state upon assigning a value into an ivar. We should probably
improve on that in the future, especially once we synthesize setters as
well as getters.
rdar://problem/18075108
llvm-svn: 228174
2015-02-05 03:24:52 +08:00
|
|
|
[_name release];
|
[analyzer] Don't track retain counts of objects directly accessed through ivars.
A refinement of r198953 to handle cases where an object is accessed both through
a property getter and through direct ivar access. An object accessed through a
property should always be treated as +0, i.e. not owned by the caller. However,
an object accessed through an ivar may be at +0 or at +1, depending on whether
the ivar is a strong reference. Outside of ARC, we don't have that information,
so we just don't track objects accessed through ivars.
With this change, accessing an ivar directly will deliberately override the +0
provided by a getter, but only if the +0 hasn't participated in other retain
counting yet. That isn't perfect, but it's already unusual for people to be
mixing property access with direct ivar access. (The primary use case for this
is in setters, init methods, and -dealloc.)
Thanks to Ted for spotting a few mistakes in private review.
<rdar://problem/16333368>
llvm-svn: 204730
2014-03-26 01:10:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
2014-01-23 11:59:10 +08:00
|
|
|
#endif
|
2014-01-11 04:06:06 +08:00
|
|
|
|
|
|
|
@interface IntWrapper
|
|
|
|
@property int value;
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation IntWrapper
|
|
|
|
@synthesize value;
|
|
|
|
@end
|
|
|
|
|
|
|
|
void testConsistencyInt(IntWrapper *w) {
|
|
|
|
clang_analyzer_eval(w.value == w.value); // expected-warning{{TRUE}}
|
|
|
|
|
|
|
|
int origValue = w.value;
|
|
|
|
if (origValue != 42)
|
|
|
|
return;
|
|
|
|
|
|
|
|
clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void testConsistencyInt2(IntWrapper *w) {
|
|
|
|
if (w.value != 42)
|
|
|
|
return;
|
|
|
|
|
|
|
|
clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}}
|
|
|
|
}
|
|
|
|
|
2014-01-23 11:59:10 +08:00
|
|
|
|
|
|
|
@interface IntWrapperAuto
|
|
|
|
@property int value;
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation IntWrapperAuto
|
|
|
|
@end
|
|
|
|
|
|
|
|
void testConsistencyIntAuto(IntWrapperAuto *w) {
|
|
|
|
clang_analyzer_eval(w.value == w.value); // expected-warning{{TRUE}}
|
|
|
|
|
|
|
|
int origValue = w.value;
|
|
|
|
if (origValue != 42)
|
|
|
|
return;
|
|
|
|
|
|
|
|
clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void testConsistencyIntAuto2(IntWrapperAuto *w) {
|
|
|
|
if (w.value != 42)
|
|
|
|
return;
|
|
|
|
|
|
|
|
clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-01-11 04:06:06 +08:00
|
|
|
typedef struct {
|
|
|
|
int value;
|
|
|
|
} IntWrapperStruct;
|
|
|
|
|
|
|
|
@interface StructWrapper
|
|
|
|
@property IntWrapperStruct inner;
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation StructWrapper
|
|
|
|
@synthesize inner;
|
|
|
|
@end
|
|
|
|
|
|
|
|
void testConsistencyStruct(StructWrapper *w) {
|
|
|
|
clang_analyzer_eval(w.inner.value == w.inner.value); // expected-warning{{TRUE}}
|
|
|
|
|
|
|
|
int origValue = w.inner.value;
|
|
|
|
if (origValue != 42)
|
|
|
|
return;
|
|
|
|
|
|
|
|
clang_analyzer_eval(w.inner.value == 42); // expected-warning{{TRUE}}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@interface OpaqueIntWrapper
|
|
|
|
@property int value;
|
|
|
|
@end
|
|
|
|
|
|
|
|
// For now, don't assume a property is implemented using an ivar unless we can
|
|
|
|
// actually see that it is.
|
|
|
|
void testOpaqueConsistency(OpaqueIntWrapper *w) {
|
|
|
|
clang_analyzer_eval(w.value == w.value); // expected-warning{{UNKNOWN}}
|
|
|
|
}
|
|
|
|
|
[analyzer] RetainCountChecker: be forgiving when ivars are accessed directly.
A refinement of r204730, itself a refinement of r198953, to better handle
cases where an object is accessed both through a property getter and
through direct ivar access. An object accessed through a property should
always be treated as +0, i.e. not owned by the caller. However, an object
accessed through an ivar may be at +0 or at +1, depending on whether the
ivar is a strong reference. Outside of ARC, we don't always have that
information.
The previous attempt would clear out the +0 provided by a getter, but only
if that +0 hadn't already participated in other retain counting operations.
(That is, "self.foo" is okay, but "[[self.foo retain] autorelease]" is
problematic.) This turned out to not be good enough when our synthesized
getters get involved.
This commit drops the notion of "overridable" reference counting and instead
just tracks whether a value ever came from a (strong) ivar. If it has, we
allow one more release than we otherwise would. This has the added benefit
of being able to catch /some/ overreleases of instance variables, though
it's not likely to come up in practice.
We do still get some false negatives because we currently throw away
refcount state upon assigning a value into an ivar. We should probably
improve on that in the future, especially once we synthesize setters as
well as getters.
rdar://problem/18075108
llvm-svn: 228174
2015-02-05 03:24:52 +08:00
|
|
|
|
|
|
|
#if !__has_feature(objc_arc)
|
|
|
|
// Test quite a few cases of retain/release issues.
|
|
|
|
|
|
|
|
@interface RetainCountTesting
|
|
|
|
@property (strong) id ownedProp;
|
|
|
|
@property (unsafe_unretained) id unownedProp;
|
|
|
|
@property (nonatomic, strong) id manualProp;
|
2015-03-21 05:12:27 +08:00
|
|
|
@property (readonly) id readonlyProp;
|
|
|
|
@property (nonatomic, readwrite/*, assign */) id implicitManualProp; // expected-warning {{'assign' is assumed}} expected-warning {{'assign' not appropriate}}
|
|
|
|
@property (nonatomic, readwrite/*, assign */) id implicitSynthProp; // expected-warning {{'assign' is assumed}} expected-warning {{'assign' not appropriate}}
|
2015-03-07 13:47:24 +08:00
|
|
|
@property CFTypeRef cfProp;
|
[analyzer] RetainCountChecker: be forgiving when ivars are accessed directly.
A refinement of r204730, itself a refinement of r198953, to better handle
cases where an object is accessed both through a property getter and
through direct ivar access. An object accessed through a property should
always be treated as +0, i.e. not owned by the caller. However, an object
accessed through an ivar may be at +0 or at +1, depending on whether the
ivar is a strong reference. Outside of ARC, we don't always have that
information.
The previous attempt would clear out the +0 provided by a getter, but only
if that +0 hadn't already participated in other retain counting operations.
(That is, "self.foo" is okay, but "[[self.foo retain] autorelease]" is
problematic.) This turned out to not be good enough when our synthesized
getters get involved.
This commit drops the notion of "overridable" reference counting and instead
just tracks whether a value ever came from a (strong) ivar. If it has, we
allow one more release than we otherwise would. This has the added benefit
of being able to catch /some/ overreleases of instance variables, though
it's not likely to come up in practice.
We do still get some false negatives because we currently throw away
refcount state upon assigning a value into an ivar. We should probably
improve on that in the future, especially once we synthesize setters as
well as getters.
rdar://problem/18075108
llvm-svn: 228174
2015-02-05 03:24:52 +08:00
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation RetainCountTesting {
|
|
|
|
id _ivarOnly;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id)manualProp {
|
|
|
|
return _manualProp;
|
|
|
|
}
|
|
|
|
|
2015-03-21 05:12:27 +08:00
|
|
|
- (void)setImplicitManualProp:(id)newValue {}
|
|
|
|
|
[analyzer] RetainCountChecker: be forgiving when ivars are accessed directly.
A refinement of r204730, itself a refinement of r198953, to better handle
cases where an object is accessed both through a property getter and
through direct ivar access. An object accessed through a property should
always be treated as +0, i.e. not owned by the caller. However, an object
accessed through an ivar may be at +0 or at +1, depending on whether the
ivar is a strong reference. Outside of ARC, we don't always have that
information.
The previous attempt would clear out the +0 provided by a getter, but only
if that +0 hadn't already participated in other retain counting operations.
(That is, "self.foo" is okay, but "[[self.foo retain] autorelease]" is
problematic.) This turned out to not be good enough when our synthesized
getters get involved.
This commit drops the notion of "overridable" reference counting and instead
just tracks whether a value ever came from a (strong) ivar. If it has, we
allow one more release than we otherwise would. This has the added benefit
of being able to catch /some/ overreleases of instance variables, though
it's not likely to come up in practice.
We do still get some false negatives because we currently throw away
refcount state upon assigning a value into an ivar. We should probably
improve on that in the future, especially once we synthesize setters as
well as getters.
rdar://problem/18075108
llvm-svn: 228174
2015-02-05 03:24:52 +08:00
|
|
|
- (void)testOverreleaseOwnedIvar {
|
|
|
|
[_ownedProp retain];
|
|
|
|
[_ownedProp release];
|
|
|
|
[_ownedProp release];
|
2015-03-31 04:18:00 +08:00
|
|
|
[_ownedProp release]; // FIXME-warning{{used after it is released}}
|
[analyzer] RetainCountChecker: be forgiving when ivars are accessed directly.
A refinement of r204730, itself a refinement of r198953, to better handle
cases where an object is accessed both through a property getter and
through direct ivar access. An object accessed through a property should
always be treated as +0, i.e. not owned by the caller. However, an object
accessed through an ivar may be at +0 or at +1, depending on whether the
ivar is a strong reference. Outside of ARC, we don't always have that
information.
The previous attempt would clear out the +0 provided by a getter, but only
if that +0 hadn't already participated in other retain counting operations.
(That is, "self.foo" is okay, but "[[self.foo retain] autorelease]" is
problematic.) This turned out to not be good enough when our synthesized
getters get involved.
This commit drops the notion of "overridable" reference counting and instead
just tracks whether a value ever came from a (strong) ivar. If it has, we
allow one more release than we otherwise would. This has the added benefit
of being able to catch /some/ overreleases of instance variables, though
it's not likely to come up in practice.
We do still get some false negatives because we currently throw away
refcount state upon assigning a value into an ivar. We should probably
improve on that in the future, especially once we synthesize setters as
well as getters.
rdar://problem/18075108
llvm-svn: 228174
2015-02-05 03:24:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)testOverreleaseUnownedIvar {
|
|
|
|
[_unownedProp retain];
|
|
|
|
[_unownedProp release];
|
2015-03-31 04:17:47 +08:00
|
|
|
[_unownedProp release]; // FIXME-warning{{not owned at this point by the caller}}
|
[analyzer] RetainCountChecker: be forgiving when ivars are accessed directly.
A refinement of r204730, itself a refinement of r198953, to better handle
cases where an object is accessed both through a property getter and
through direct ivar access. An object accessed through a property should
always be treated as +0, i.e. not owned by the caller. However, an object
accessed through an ivar may be at +0 or at +1, depending on whether the
ivar is a strong reference. Outside of ARC, we don't always have that
information.
The previous attempt would clear out the +0 provided by a getter, but only
if that +0 hadn't already participated in other retain counting operations.
(That is, "self.foo" is okay, but "[[self.foo retain] autorelease]" is
problematic.) This turned out to not be good enough when our synthesized
getters get involved.
This commit drops the notion of "overridable" reference counting and instead
just tracks whether a value ever came from a (strong) ivar. If it has, we
allow one more release than we otherwise would. This has the added benefit
of being able to catch /some/ overreleases of instance variables, though
it's not likely to come up in practice.
We do still get some false negatives because we currently throw away
refcount state upon assigning a value into an ivar. We should probably
improve on that in the future, especially once we synthesize setters as
well as getters.
rdar://problem/18075108
llvm-svn: 228174
2015-02-05 03:24:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)testOverreleaseIvarOnly {
|
|
|
|
[_ivarOnly retain];
|
|
|
|
[_ivarOnly release];
|
|
|
|
[_ivarOnly release];
|
2015-03-31 04:18:00 +08:00
|
|
|
[_ivarOnly release]; // FIXME-warning{{used after it is released}}
|
[analyzer] RetainCountChecker: be forgiving when ivars are accessed directly.
A refinement of r204730, itself a refinement of r198953, to better handle
cases where an object is accessed both through a property getter and
through direct ivar access. An object accessed through a property should
always be treated as +0, i.e. not owned by the caller. However, an object
accessed through an ivar may be at +0 or at +1, depending on whether the
ivar is a strong reference. Outside of ARC, we don't always have that
information.
The previous attempt would clear out the +0 provided by a getter, but only
if that +0 hadn't already participated in other retain counting operations.
(That is, "self.foo" is okay, but "[[self.foo retain] autorelease]" is
problematic.) This turned out to not be good enough when our synthesized
getters get involved.
This commit drops the notion of "overridable" reference counting and instead
just tracks whether a value ever came from a (strong) ivar. If it has, we
allow one more release than we otherwise would. This has the added benefit
of being able to catch /some/ overreleases of instance variables, though
it's not likely to come up in practice.
We do still get some false negatives because we currently throw away
refcount state upon assigning a value into an ivar. We should probably
improve on that in the future, especially once we synthesize setters as
well as getters.
rdar://problem/18075108
llvm-svn: 228174
2015-02-05 03:24:52 +08:00
|
|
|
}
|
|
|
|
|
2015-03-21 05:12:27 +08:00
|
|
|
- (void)testOverreleaseReadonlyIvar {
|
|
|
|
[_readonlyProp retain];
|
|
|
|
[_readonlyProp release];
|
|
|
|
[_readonlyProp release];
|
2015-03-31 04:18:00 +08:00
|
|
|
[_readonlyProp release]; // FIXME-warning{{used after it is released}}
|
2015-03-21 05:12:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)testOverreleaseImplicitManualIvar {
|
|
|
|
[_implicitManualProp retain];
|
|
|
|
[_implicitManualProp release];
|
|
|
|
[_implicitManualProp release];
|
2015-03-31 04:18:00 +08:00
|
|
|
[_implicitManualProp release]; // FIXME-warning{{used after it is released}}
|
2015-03-21 05:12:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)testOverreleaseImplicitSynthIvar {
|
|
|
|
[_implicitSynthProp retain];
|
|
|
|
[_implicitSynthProp release];
|
2015-03-31 04:17:47 +08:00
|
|
|
[_implicitSynthProp release]; // FIXME-warning{{not owned at this point by the caller}}
|
2015-03-21 05:12:27 +08:00
|
|
|
}
|
|
|
|
|
2015-03-07 13:47:24 +08:00
|
|
|
- (void)testOverreleaseCF {
|
|
|
|
CFRetain(_cfProp);
|
|
|
|
CFRelease(_cfProp);
|
|
|
|
CFRelease(_cfProp);
|
2015-03-31 04:18:00 +08:00
|
|
|
CFRelease(_cfProp); // FIXME-warning{{used after it is released}}
|
2015-03-07 13:47:24 +08:00
|
|
|
}
|
|
|
|
|
[analyzer] RetainCountChecker: be forgiving when ivars are accessed directly.
A refinement of r204730, itself a refinement of r198953, to better handle
cases where an object is accessed both through a property getter and
through direct ivar access. An object accessed through a property should
always be treated as +0, i.e. not owned by the caller. However, an object
accessed through an ivar may be at +0 or at +1, depending on whether the
ivar is a strong reference. Outside of ARC, we don't always have that
information.
The previous attempt would clear out the +0 provided by a getter, but only
if that +0 hadn't already participated in other retain counting operations.
(That is, "self.foo" is okay, but "[[self.foo retain] autorelease]" is
problematic.) This turned out to not be good enough when our synthesized
getters get involved.
This commit drops the notion of "overridable" reference counting and instead
just tracks whether a value ever came from a (strong) ivar. If it has, we
allow one more release than we otherwise would. This has the added benefit
of being able to catch /some/ overreleases of instance variables, though
it's not likely to come up in practice.
We do still get some false negatives because we currently throw away
refcount state upon assigning a value into an ivar. We should probably
improve on that in the future, especially once we synthesize setters as
well as getters.
rdar://problem/18075108
llvm-svn: 228174
2015-02-05 03:24:52 +08:00
|
|
|
- (void)testOverreleaseOwnedIvarUse {
|
|
|
|
[_ownedProp retain];
|
|
|
|
[_ownedProp release];
|
|
|
|
[_ownedProp release];
|
2015-03-31 04:18:00 +08:00
|
|
|
[_ownedProp myMethod]; // FIXME-warning{{used after it is released}}
|
[analyzer] RetainCountChecker: be forgiving when ivars are accessed directly.
A refinement of r204730, itself a refinement of r198953, to better handle
cases where an object is accessed both through a property getter and
through direct ivar access. An object accessed through a property should
always be treated as +0, i.e. not owned by the caller. However, an object
accessed through an ivar may be at +0 or at +1, depending on whether the
ivar is a strong reference. Outside of ARC, we don't always have that
information.
The previous attempt would clear out the +0 provided by a getter, but only
if that +0 hadn't already participated in other retain counting operations.
(That is, "self.foo" is okay, but "[[self.foo retain] autorelease]" is
problematic.) This turned out to not be good enough when our synthesized
getters get involved.
This commit drops the notion of "overridable" reference counting and instead
just tracks whether a value ever came from a (strong) ivar. If it has, we
allow one more release than we otherwise would. This has the added benefit
of being able to catch /some/ overreleases of instance variables, though
it's not likely to come up in practice.
We do still get some false negatives because we currently throw away
refcount state upon assigning a value into an ivar. We should probably
improve on that in the future, especially once we synthesize setters as
well as getters.
rdar://problem/18075108
llvm-svn: 228174
2015-02-05 03:24:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)testOverreleaseIvarOnlyUse {
|
|
|
|
[_ivarOnly retain];
|
|
|
|
[_ivarOnly release];
|
|
|
|
[_ivarOnly release];
|
2015-03-31 04:18:00 +08:00
|
|
|
[_ivarOnly myMethod]; // FIXME-warning{{used after it is released}}
|
[analyzer] RetainCountChecker: be forgiving when ivars are accessed directly.
A refinement of r204730, itself a refinement of r198953, to better handle
cases where an object is accessed both through a property getter and
through direct ivar access. An object accessed through a property should
always be treated as +0, i.e. not owned by the caller. However, an object
accessed through an ivar may be at +0 or at +1, depending on whether the
ivar is a strong reference. Outside of ARC, we don't always have that
information.
The previous attempt would clear out the +0 provided by a getter, but only
if that +0 hadn't already participated in other retain counting operations.
(That is, "self.foo" is okay, but "[[self.foo retain] autorelease]" is
problematic.) This turned out to not be good enough when our synthesized
getters get involved.
This commit drops the notion of "overridable" reference counting and instead
just tracks whether a value ever came from a (strong) ivar. If it has, we
allow one more release than we otherwise would. This has the added benefit
of being able to catch /some/ overreleases of instance variables, though
it's not likely to come up in practice.
We do still get some false negatives because we currently throw away
refcount state upon assigning a value into an ivar. We should probably
improve on that in the future, especially once we synthesize setters as
well as getters.
rdar://problem/18075108
llvm-svn: 228174
2015-02-05 03:24:52 +08:00
|
|
|
}
|
|
|
|
|
2015-03-07 13:47:24 +08:00
|
|
|
- (void)testOverreleaseCFUse {
|
|
|
|
CFRetain(_cfProp);
|
|
|
|
CFRelease(_cfProp);
|
|
|
|
CFRelease(_cfProp);
|
|
|
|
|
|
|
|
extern void CFUse(CFTypeRef);
|
2015-03-31 04:18:00 +08:00
|
|
|
CFUse(_cfProp); // FIXME-warning{{used after it is released}}
|
2015-03-07 13:47:24 +08:00
|
|
|
}
|
|
|
|
|
[analyzer] RetainCountChecker: be forgiving when ivars are accessed directly.
A refinement of r204730, itself a refinement of r198953, to better handle
cases where an object is accessed both through a property getter and
through direct ivar access. An object accessed through a property should
always be treated as +0, i.e. not owned by the caller. However, an object
accessed through an ivar may be at +0 or at +1, depending on whether the
ivar is a strong reference. Outside of ARC, we don't always have that
information.
The previous attempt would clear out the +0 provided by a getter, but only
if that +0 hadn't already participated in other retain counting operations.
(That is, "self.foo" is okay, but "[[self.foo retain] autorelease]" is
problematic.) This turned out to not be good enough when our synthesized
getters get involved.
This commit drops the notion of "overridable" reference counting and instead
just tracks whether a value ever came from a (strong) ivar. If it has, we
allow one more release than we otherwise would. This has the added benefit
of being able to catch /some/ overreleases of instance variables, though
it's not likely to come up in practice.
We do still get some false negatives because we currently throw away
refcount state upon assigning a value into an ivar. We should probably
improve on that in the future, especially once we synthesize setters as
well as getters.
rdar://problem/18075108
llvm-svn: 228174
2015-02-05 03:24:52 +08:00
|
|
|
- (void)testOverreleaseOwnedIvarAutoreleaseOkay {
|
|
|
|
[_ownedProp retain];
|
|
|
|
[_ownedProp release];
|
|
|
|
[_ownedProp autorelease];
|
|
|
|
} // no-warning
|
|
|
|
|
|
|
|
- (void)testOverreleaseIvarOnlyAutoreleaseOkay {
|
|
|
|
[_ivarOnly retain];
|
|
|
|
[_ivarOnly release];
|
|
|
|
[_ivarOnly autorelease];
|
|
|
|
} // no-warning
|
|
|
|
|
|
|
|
- (void)testOverreleaseOwnedIvarAutorelease {
|
|
|
|
[_ownedProp retain];
|
|
|
|
[_ownedProp release];
|
|
|
|
[_ownedProp autorelease];
|
|
|
|
[_ownedProp autorelease];
|
2015-03-31 04:18:00 +08:00
|
|
|
} // FIXME-warning{{Object autoreleased too many times}}
|
[analyzer] RetainCountChecker: be forgiving when ivars are accessed directly.
A refinement of r204730, itself a refinement of r198953, to better handle
cases where an object is accessed both through a property getter and
through direct ivar access. An object accessed through a property should
always be treated as +0, i.e. not owned by the caller. However, an object
accessed through an ivar may be at +0 or at +1, depending on whether the
ivar is a strong reference. Outside of ARC, we don't always have that
information.
The previous attempt would clear out the +0 provided by a getter, but only
if that +0 hadn't already participated in other retain counting operations.
(That is, "self.foo" is okay, but "[[self.foo retain] autorelease]" is
problematic.) This turned out to not be good enough when our synthesized
getters get involved.
This commit drops the notion of "overridable" reference counting and instead
just tracks whether a value ever came from a (strong) ivar. If it has, we
allow one more release than we otherwise would. This has the added benefit
of being able to catch /some/ overreleases of instance variables, though
it's not likely to come up in practice.
We do still get some false negatives because we currently throw away
refcount state upon assigning a value into an ivar. We should probably
improve on that in the future, especially once we synthesize setters as
well as getters.
rdar://problem/18075108
llvm-svn: 228174
2015-02-05 03:24:52 +08:00
|
|
|
|
|
|
|
- (void)testOverreleaseIvarOnlyAutorelease {
|
|
|
|
[_ivarOnly retain];
|
|
|
|
[_ivarOnly release];
|
|
|
|
[_ivarOnly autorelease];
|
|
|
|
[_ivarOnly autorelease];
|
2015-03-31 04:18:00 +08:00
|
|
|
} // FIXME-warning{{Object autoreleased too many times}}
|
[analyzer] RetainCountChecker: be forgiving when ivars are accessed directly.
A refinement of r204730, itself a refinement of r198953, to better handle
cases where an object is accessed both through a property getter and
through direct ivar access. An object accessed through a property should
always be treated as +0, i.e. not owned by the caller. However, an object
accessed through an ivar may be at +0 or at +1, depending on whether the
ivar is a strong reference. Outside of ARC, we don't always have that
information.
The previous attempt would clear out the +0 provided by a getter, but only
if that +0 hadn't already participated in other retain counting operations.
(That is, "self.foo" is okay, but "[[self.foo retain] autorelease]" is
problematic.) This turned out to not be good enough when our synthesized
getters get involved.
This commit drops the notion of "overridable" reference counting and instead
just tracks whether a value ever came from a (strong) ivar. If it has, we
allow one more release than we otherwise would. This has the added benefit
of being able to catch /some/ overreleases of instance variables, though
it's not likely to come up in practice.
We do still get some false negatives because we currently throw away
refcount state upon assigning a value into an ivar. We should probably
improve on that in the future, especially once we synthesize setters as
well as getters.
rdar://problem/18075108
llvm-svn: 228174
2015-02-05 03:24:52 +08:00
|
|
|
|
|
|
|
- (void)testPropertyAccessThenReleaseOwned {
|
|
|
|
id owned = [self.ownedProp retain];
|
|
|
|
[owned release];
|
|
|
|
[_ownedProp release];
|
|
|
|
clang_analyzer_eval(owned == _ownedProp); // expected-warning{{TRUE}}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)testPropertyAccessThenReleaseOwned2 {
|
|
|
|
id fromIvar = _ownedProp;
|
|
|
|
id owned = [self.ownedProp retain];
|
|
|
|
[owned release];
|
|
|
|
[fromIvar release];
|
|
|
|
clang_analyzer_eval(owned == fromIvar); // expected-warning{{TRUE}}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)testPropertyAccessThenReleaseUnowned {
|
|
|
|
id unowned = [self.unownedProp retain];
|
|
|
|
[unowned release];
|
2015-03-31 04:17:47 +08:00
|
|
|
[_unownedProp release]; // FIXME-warning{{not owned}}
|
[analyzer] RetainCountChecker: be forgiving when ivars are accessed directly.
A refinement of r204730, itself a refinement of r198953, to better handle
cases where an object is accessed both through a property getter and
through direct ivar access. An object accessed through a property should
always be treated as +0, i.e. not owned by the caller. However, an object
accessed through an ivar may be at +0 or at +1, depending on whether the
ivar is a strong reference. Outside of ARC, we don't always have that
information.
The previous attempt would clear out the +0 provided by a getter, but only
if that +0 hadn't already participated in other retain counting operations.
(That is, "self.foo" is okay, but "[[self.foo retain] autorelease]" is
problematic.) This turned out to not be good enough when our synthesized
getters get involved.
This commit drops the notion of "overridable" reference counting and instead
just tracks whether a value ever came from a (strong) ivar. If it has, we
allow one more release than we otherwise would. This has the added benefit
of being able to catch /some/ overreleases of instance variables, though
it's not likely to come up in practice.
We do still get some false negatives because we currently throw away
refcount state upon assigning a value into an ivar. We should probably
improve on that in the future, especially once we synthesize setters as
well as getters.
rdar://problem/18075108
llvm-svn: 228174
2015-02-05 03:24:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)testPropertyAccessThenReleaseUnowned2 {
|
|
|
|
id fromIvar = _unownedProp;
|
|
|
|
id unowned = [self.unownedProp retain];
|
|
|
|
[unowned release];
|
|
|
|
clang_analyzer_eval(unowned == fromIvar); // expected-warning{{TRUE}}
|
2015-03-31 04:17:47 +08:00
|
|
|
[fromIvar release]; // FIXME-warning{{not owned}}
|
[analyzer] RetainCountChecker: be forgiving when ivars are accessed directly.
A refinement of r204730, itself a refinement of r198953, to better handle
cases where an object is accessed both through a property getter and
through direct ivar access. An object accessed through a property should
always be treated as +0, i.e. not owned by the caller. However, an object
accessed through an ivar may be at +0 or at +1, depending on whether the
ivar is a strong reference. Outside of ARC, we don't always have that
information.
The previous attempt would clear out the +0 provided by a getter, but only
if that +0 hadn't already participated in other retain counting operations.
(That is, "self.foo" is okay, but "[[self.foo retain] autorelease]" is
problematic.) This turned out to not be good enough when our synthesized
getters get involved.
This commit drops the notion of "overridable" reference counting and instead
just tracks whether a value ever came from a (strong) ivar. If it has, we
allow one more release than we otherwise would. This has the added benefit
of being able to catch /some/ overreleases of instance variables, though
it's not likely to come up in practice.
We do still get some false negatives because we currently throw away
refcount state upon assigning a value into an ivar. We should probably
improve on that in the future, especially once we synthesize setters as
well as getters.
rdar://problem/18075108
llvm-svn: 228174
2015-02-05 03:24:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)testPropertyAccessThenReleaseManual {
|
|
|
|
id prop = [self.manualProp retain];
|
|
|
|
[prop release];
|
|
|
|
[_manualProp release]; // no-warning
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)testPropertyAccessThenReleaseManual2 {
|
|
|
|
id fromIvar = _manualProp;
|
|
|
|
id prop = [self.manualProp retain];
|
|
|
|
[prop release];
|
|
|
|
clang_analyzer_eval(prop == fromIvar); // expected-warning{{TRUE}}
|
|
|
|
[fromIvar release]; // no-warning
|
|
|
|
}
|
|
|
|
|
2015-03-07 13:47:24 +08:00
|
|
|
- (void)testPropertyAccessThenReleaseCF {
|
|
|
|
CFTypeRef owned = CFRetain(self.cfProp);
|
|
|
|
CFRelease(owned);
|
|
|
|
CFRelease(_cfProp); // no-warning
|
|
|
|
clang_analyzer_eval(owned == _cfProp); // expected-warning{{TRUE}}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)testPropertyAccessThenReleaseCF2 {
|
|
|
|
CFTypeRef fromIvar = _cfProp;
|
|
|
|
CFTypeRef owned = CFRetain(self.cfProp);
|
|
|
|
CFRelease(owned);
|
|
|
|
CFRelease(fromIvar);
|
|
|
|
clang_analyzer_eval(owned == fromIvar); // expected-warning{{TRUE}}
|
|
|
|
}
|
|
|
|
|
2015-03-21 05:12:27 +08:00
|
|
|
- (void)testPropertyAccessThenReleaseReadonly {
|
|
|
|
id prop = [self.readonlyProp retain];
|
|
|
|
[prop release];
|
|
|
|
[_readonlyProp release]; // no-warning
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)testPropertyAccessThenReleaseReadonly2 {
|
|
|
|
id fromIvar = _readonlyProp;
|
|
|
|
id prop = [self.readonlyProp retain];
|
|
|
|
[prop release];
|
|
|
|
clang_analyzer_eval(prop == fromIvar); // expected-warning{{TRUE}}
|
|
|
|
[fromIvar release]; // no-warning
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)testPropertyAccessThenReleaseImplicitManual {
|
|
|
|
id prop = [self.implicitManualProp retain];
|
|
|
|
[prop release];
|
|
|
|
[_implicitManualProp release]; // no-warning
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)testPropertyAccessThenReleaseImplicitManual2 {
|
|
|
|
id fromIvar = _implicitManualProp;
|
|
|
|
id prop = [self.implicitManualProp retain];
|
|
|
|
[prop release];
|
|
|
|
clang_analyzer_eval(prop == fromIvar); // expected-warning{{TRUE}}
|
|
|
|
[fromIvar release]; // no-warning
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)testPropertyAccessThenReleaseImplicitSynth {
|
|
|
|
id prop = [self.implicitSynthProp retain];
|
|
|
|
[prop release];
|
2015-03-31 04:17:47 +08:00
|
|
|
[_implicitSynthProp release]; // FIXME-warning{{not owned}}
|
2015-03-21 05:12:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)testPropertyAccessThenReleaseImplicitSynth2 {
|
|
|
|
id fromIvar = _implicitSynthProp;
|
|
|
|
id prop = [self.implicitSynthProp retain];
|
|
|
|
[prop release];
|
|
|
|
clang_analyzer_eval(prop == fromIvar); // expected-warning{{TRUE}}
|
2015-03-31 04:17:47 +08:00
|
|
|
[fromIvar release]; // FIXME-warning{{not owned}}
|
2015-03-21 05:12:27 +08:00
|
|
|
}
|
|
|
|
|
[analyzer] RetainCountChecker: be forgiving when ivars are accessed directly.
A refinement of r204730, itself a refinement of r198953, to better handle
cases where an object is accessed both through a property getter and
through direct ivar access. An object accessed through a property should
always be treated as +0, i.e. not owned by the caller. However, an object
accessed through an ivar may be at +0 or at +1, depending on whether the
ivar is a strong reference. Outside of ARC, we don't always have that
information.
The previous attempt would clear out the +0 provided by a getter, but only
if that +0 hadn't already participated in other retain counting operations.
(That is, "self.foo" is okay, but "[[self.foo retain] autorelease]" is
problematic.) This turned out to not be good enough when our synthesized
getters get involved.
This commit drops the notion of "overridable" reference counting and instead
just tracks whether a value ever came from a (strong) ivar. If it has, we
allow one more release than we otherwise would. This has the added benefit
of being able to catch /some/ overreleases of instance variables, though
it's not likely to come up in practice.
We do still get some false negatives because we currently throw away
refcount state upon assigning a value into an ivar. We should probably
improve on that in the future, especially once we synthesize setters as
well as getters.
rdar://problem/18075108
llvm-svn: 228174
2015-02-05 03:24:52 +08:00
|
|
|
- (id)getUnownedFromProperty {
|
|
|
|
[_ownedProp retain];
|
|
|
|
[_ownedProp autorelease];
|
|
|
|
return _ownedProp; // no-warning
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id)transferUnownedFromProperty {
|
|
|
|
[_ownedProp retain];
|
|
|
|
[_ownedProp autorelease];
|
|
|
|
return [_ownedProp autorelease]; // no-warning
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id)transferOwnedFromProperty __attribute__((ns_returns_retained)) {
|
|
|
|
[_ownedProp retain];
|
|
|
|
[_ownedProp autorelease];
|
|
|
|
return _ownedProp; // no-warning
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)testAssignOwned:(id)newValue {
|
|
|
|
_ownedProp = newValue;
|
|
|
|
[_ownedProp release]; // FIXME: no-warning{{not owned}}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)testAssignUnowned:(id)newValue {
|
|
|
|
_unownedProp = newValue;
|
|
|
|
[_unownedProp release]; // FIXME: no-warning{{not owned}}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)testAssignIvarOnly:(id)newValue {
|
|
|
|
_ivarOnly = newValue;
|
|
|
|
[_ivarOnly release]; // FIXME: no-warning{{not owned}}
|
|
|
|
}
|
|
|
|
|
2015-03-07 13:47:24 +08:00
|
|
|
- (void)testAssignCF:(CFTypeRef)newValue {
|
|
|
|
_cfProp = newValue;
|
|
|
|
CFRelease(_cfProp); // FIXME: no-warning{{not owned}}
|
|
|
|
}
|
|
|
|
|
2015-03-21 05:12:27 +08:00
|
|
|
- (void)testAssignReadonly:(id)newValue {
|
|
|
|
_readonlyProp = newValue;
|
|
|
|
[_readonlyProp release]; // FIXME: no-warning{{not owned}}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)testAssignImplicitManual:(id)newValue {
|
|
|
|
_implicitManualProp = newValue;
|
|
|
|
[_implicitManualProp release]; // FIXME: no-warning{{not owned}}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)testAssignImplicitSynth:(id)newValue {
|
|
|
|
_implicitSynthProp = newValue;
|
|
|
|
[_implicitSynthProp release]; // FIXME: no-warning{{not owned}}
|
|
|
|
}
|
|
|
|
|
[analyzer] RetainCountChecker: be forgiving when ivars are accessed directly.
A refinement of r204730, itself a refinement of r198953, to better handle
cases where an object is accessed both through a property getter and
through direct ivar access. An object accessed through a property should
always be treated as +0, i.e. not owned by the caller. However, an object
accessed through an ivar may be at +0 or at +1, depending on whether the
ivar is a strong reference. Outside of ARC, we don't always have that
information.
The previous attempt would clear out the +0 provided by a getter, but only
if that +0 hadn't already participated in other retain counting operations.
(That is, "self.foo" is okay, but "[[self.foo retain] autorelease]" is
problematic.) This turned out to not be good enough when our synthesized
getters get involved.
This commit drops the notion of "overridable" reference counting and instead
just tracks whether a value ever came from a (strong) ivar. If it has, we
allow one more release than we otherwise would. This has the added benefit
of being able to catch /some/ overreleases of instance variables, though
it's not likely to come up in practice.
We do still get some false negatives because we currently throw away
refcount state upon assigning a value into an ivar. We should probably
improve on that in the future, especially once we synthesize setters as
well as getters.
rdar://problem/18075108
llvm-svn: 228174
2015-02-05 03:24:52 +08:00
|
|
|
- (void)testAssignOwnedOkay:(id)newValue {
|
|
|
|
_ownedProp = [newValue retain];
|
|
|
|
[_ownedProp release]; // no-warning
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)testAssignUnownedOkay:(id)newValue {
|
|
|
|
_unownedProp = [newValue retain];
|
|
|
|
[_unownedProp release]; // no-warning
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)testAssignIvarOnlyOkay:(id)newValue {
|
|
|
|
_ivarOnly = [newValue retain];
|
|
|
|
[_ivarOnly release]; // no-warning
|
|
|
|
}
|
|
|
|
|
2015-03-07 13:47:24 +08:00
|
|
|
- (void)testAssignCFOkay:(CFTypeRef)newValue {
|
|
|
|
_cfProp = CFRetain(newValue);
|
|
|
|
CFRelease(_cfProp); // no-warning
|
|
|
|
}
|
|
|
|
|
2015-03-21 05:12:27 +08:00
|
|
|
- (void)testAssignReadonlyOkay:(id)newValue {
|
|
|
|
_readonlyProp = [newValue retain];
|
|
|
|
[_readonlyProp release]; // FIXME: no-warning{{not owned}}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)testAssignImplicitManualOkay:(id)newValue {
|
|
|
|
_implicitManualProp = [newValue retain];
|
|
|
|
[_implicitManualProp release]; // FIXME: no-warning{{not owned}}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)testAssignImplicitSynthOkay:(id)newValue {
|
|
|
|
_implicitSynthProp = [newValue retain];
|
|
|
|
[_implicitSynthProp release]; // FIXME: no-warning{{not owned}}
|
|
|
|
}
|
|
|
|
|
2015-02-20 07:57:04 +08:00
|
|
|
// rdar://problem/19862648
|
|
|
|
- (void)establishIvarIsNilDuringLoops {
|
|
|
|
extern id getRandomObject();
|
|
|
|
|
|
|
|
int i = 4; // Must be at least 4 to trigger the bug.
|
|
|
|
while (--i) {
|
|
|
|
id x = 0;
|
|
|
|
if (getRandomObject())
|
|
|
|
x = _ivarOnly;
|
|
|
|
if (!x)
|
|
|
|
x = getRandomObject();
|
|
|
|
[x myMethod];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-31 04:18:04 +08:00
|
|
|
// rdar://problem/20335433
|
|
|
|
- (void)retainIvarAndInvalidateSelf {
|
|
|
|
extern void invalidate(id);
|
|
|
|
[_unownedProp retain];
|
|
|
|
invalidate(self);
|
|
|
|
[_unownedProp release]; // no-warning
|
|
|
|
}
|
|
|
|
|
[analyzer] RetainCountChecker: be forgiving when ivars are accessed directly.
A refinement of r204730, itself a refinement of r198953, to better handle
cases where an object is accessed both through a property getter and
through direct ivar access. An object accessed through a property should
always be treated as +0, i.e. not owned by the caller. However, an object
accessed through an ivar may be at +0 or at +1, depending on whether the
ivar is a strong reference. Outside of ARC, we don't always have that
information.
The previous attempt would clear out the +0 provided by a getter, but only
if that +0 hadn't already participated in other retain counting operations.
(That is, "self.foo" is okay, but "[[self.foo retain] autorelease]" is
problematic.) This turned out to not be good enough when our synthesized
getters get involved.
This commit drops the notion of "overridable" reference counting and instead
just tracks whether a value ever came from a (strong) ivar. If it has, we
allow one more release than we otherwise would. This has the added benefit
of being able to catch /some/ overreleases of instance variables, though
it's not likely to come up in practice.
We do still get some false negatives because we currently throw away
refcount state upon assigning a value into an ivar. We should probably
improve on that in the future, especially once we synthesize setters as
well as getters.
rdar://problem/18075108
llvm-svn: 228174
2015-02-05 03:24:52 +08:00
|
|
|
@end
|
|
|
|
#endif // non-ARC
|
|
|
|
|