Mercurial > hg > CbC > CbC_llvm
diff clang/test/Analysis/DeallocUseAfterFreeErrors.m @ 150:1d019706d866
LLVM10
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 15:10:13 +0900 |
parents | |
children | c4bab56944e8 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/clang/test/Analysis/DeallocUseAfterFreeErrors.m Thu Feb 13 15:10:13 2020 +0900 @@ -0,0 +1,373 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.SuperDealloc,debug.ExprInspection -analyzer-output=text -verify %s + +void clang_analyzer_warnIfReached(); + +#define nil ((id)0) + +typedef unsigned long NSUInteger; +@protocol NSObject +- (instancetype)retain; +- (oneway void)release; +@end + +@interface NSObject <NSObject> { } +- (void)dealloc; +- (instancetype)init; +@end + +typedef struct objc_selector *SEL; + +//===------------------------------------------------------------------------=== +// <rdar://problem/6953275> +// Check that 'self' is not referenced after calling '[super dealloc]'. + +@interface SuperDeallocThenReleaseIvarClass : NSObject { + NSObject *_ivar; +} +@end + +@implementation SuperDeallocThenReleaseIvarClass +- (instancetype)initWithIvar:(NSObject *)ivar { + self = [super init]; + if (!self) + return nil; + _ivar = [ivar retain]; + return self; +} +- (void)dealloc { + [super dealloc]; // expected-note {{[super dealloc] called here}} + [_ivar release]; // expected-warning {{Use of instance variable '_ivar' after 'self' has been deallocated}} + // expected-note@-1 {{Use of instance variable '_ivar' after 'self' has been deallocated}} +} +@end + +@interface SuperDeallocThenAssignNilToIvarClass : NSObject { + NSObject *_delegate; +} +@end + +@implementation SuperDeallocThenAssignNilToIvarClass +- (instancetype)initWithDelegate:(NSObject *)delegate { + self = [super init]; + if (!self) + return nil; + _delegate = delegate; + return self; +} +- (void)dealloc { + [super dealloc]; // expected-note {{[super dealloc] called here}} + _delegate = nil; // expected-warning {{Use of instance variable '_delegate' after 'self' has been deallocated}} + // expected-note@-1 {{Use of instance variable '_delegate' after 'self' has been deallocated}} +} +@end + + +struct SomeStruct { + int f; +}; + +@interface SuperDeallocThenAssignIvarField : NSObject { + struct SomeStruct _s; +} +@end + +@implementation SuperDeallocThenAssignIvarField +- (void)dealloc { + [super dealloc]; // expected-note {{[super dealloc] called here}} + _s.f = 7; // expected-warning {{Use of instance variable '_s' after 'self' has been deallocated}} + // expected-note@-1 {{Use of instance variable '_s' after 'self' has been deallocated}} +} +@end + +@interface OtherClassWithIvar { +@public + int _otherIvar; +} +@end; + +@interface SuperDeallocThenAssignIvarIvar : NSObject { + OtherClassWithIvar *_ivar; +} +@end + +@implementation SuperDeallocThenAssignIvarIvar +- (void)dealloc { + [super dealloc]; // expected-note {{[super dealloc] called here}} + _ivar->_otherIvar = 7; // expected-warning {{Use of instance variable '_ivar' after 'self' has been deallocated}} + // expected-note@-1 {{Use of instance variable '_ivar' after 'self' has been deallocated}} +} +@end + +@interface SuperDeallocThenAssignSelfIvar : NSObject { + NSObject *_ivar; +} +@end + +@implementation SuperDeallocThenAssignSelfIvar +- (void)dealloc { + [super dealloc]; // expected-note {{[super dealloc] called here}} + self->_ivar = nil; // expected-warning {{Use of instance variable '_ivar' after 'self' has been deallocated}} + // expected-note@-1 {{Use of instance variable '_ivar' after 'self' has been deallocated}} +} +@end + +@interface SuperDeallocThenReleasePropertyClass : NSObject { } +@property (retain) NSObject *ivar; +@end + +@implementation SuperDeallocThenReleasePropertyClass +- (instancetype)initWithProperty:(NSObject *)ivar { + self = [super init]; + if (!self) + return nil; + self.ivar = ivar; + return self; +} +- (void)dealloc { + [super dealloc]; // expected-note {{[super dealloc] called here}} + self.ivar = nil; // expected-warning {{Use of 'self' after it has been deallocated}} + // expected-note@-1 {{Use of 'self' after it has been deallocated}} +} +@end + +@interface SuperDeallocThenAssignNilToPropertyClass : NSObject { } +@property (assign) NSObject *delegate; +@end + +@implementation SuperDeallocThenAssignNilToPropertyClass +- (instancetype)initWithDelegate:(NSObject *)delegate { + self = [super init]; + if (!self) + return nil; + self.delegate = delegate; + return self; +} +- (void)dealloc { + [super dealloc]; // expected-note {{[super dealloc] called here}} + self.delegate = nil; // expected-warning {{Use of 'self' after it has been deallocated}} + // expected-note@-1 {{Use of 'self' after it has been deallocated}} +} +@end + +@interface SuperDeallocThenCallInstanceMethodClass : NSObject { } +- (void)_invalidate; +@end + +@implementation SuperDeallocThenCallInstanceMethodClass +- (void)_invalidate { +} +- (void)dealloc { + [super dealloc]; // expected-note {{[super dealloc] called here}} + [self _invalidate]; // expected-warning {{Use of 'self' after it has been deallocated}} + // expected-note@-1 {{Use of 'self' after it has been deallocated}} +} +@end + +@interface SuperDeallocThenCallNonObjectiveCMethodClass : NSObject { } +@end + +static void _invalidate(NSObject *object) { + (void)object; +} + +@implementation SuperDeallocThenCallNonObjectiveCMethodClass +- (void)dealloc { + [super dealloc]; // expected-note {{[super dealloc] called here}} + _invalidate(self); // expected-warning {{Use of 'self' after it has been deallocated}} + // expected-note@-1 {{Use of 'self' after it has been deallocated}} +} +@end + +@interface SuperDeallocThenCallObjectiveClassMethodClass : NSObject { } +@end + +@implementation SuperDeallocThenCallObjectiveClassMethodClass ++ (void) invalidate:(id)arg; { +} + +- (void)dealloc { + [super dealloc]; // expected-note {{[super dealloc] called here}} + [SuperDeallocThenCallObjectiveClassMethodClass invalidate:self]; // expected-warning {{Use of 'self' after it has been deallocated}} + // expected-note@-1 {{Use of 'self' after it has been deallocated}} +} +@end + +@interface TwoSuperDeallocCallsClass : NSObject { + NSObject *_ivar; +} +- (void)_invalidate; +@end + +@implementation TwoSuperDeallocCallsClass +- (void)_invalidate { +} +- (void)dealloc { + if (_ivar) { // expected-note {{Assuming the condition is false}} expected-note {{Taking false branch}} + [_ivar release]; + [super dealloc]; + return; + } + [super dealloc]; // expected-note {{[super dealloc] called here}} + [self _invalidate]; // expected-warning {{Use of 'self' after it has been deallocated}} + // expected-note@-1 {{Use of 'self' after it has been deallocated}} +} +@end + +//===------------------------------------------------------------------------=== +// Warn about calling [super dealloc] twice due to missing return statement. + +@interface MissingReturnCausesDoubleSuperDeallocClass : NSObject { + NSObject *_ivar; +} +@end + +@implementation MissingReturnCausesDoubleSuperDeallocClass +- (void)dealloc { + if (_ivar) { // expected-note {{Assuming the condition is true}} expected-note {{Taking true branch}} + [_ivar release]; + [super dealloc]; // expected-note {{[super dealloc] called here}} + // return; + } + [super dealloc]; // expected-warning{{[super dealloc] should not be called multiple times}} + // expected-note@-1{{[super dealloc] should not be called multiple times}} +} +@end + +//===------------------------------------------------------------------------=== +// Warn about calling [super dealloc] twice in two different methods. + +@interface SuperDeallocInOtherMethodClass : NSObject { + NSObject *_ivar; +} +- (void)_cleanup; +@end + +@implementation SuperDeallocInOtherMethodClass +- (void)_cleanup { + [_ivar release]; + [super dealloc]; // expected-note {{[super dealloc] called here}} +} +- (void)dealloc { + [self _cleanup]; // expected-note {{Calling '_cleanup'}} + //expected-note@-1 {{Returning from '_cleanup'}} + [super dealloc]; // expected-warning {{[super dealloc] should not be called multiple times}} + // expected-note@-1 {{[super dealloc] should not be called multiple times}} +} +@end + +//===------------------------------------------------------------------------=== +// Do not warn about calling [super dealloc] recursively for different objects +// of the same type with custom retain counting. +// +// A class that contains an ivar of itself with custom retain counting (such +// as provided by _OBJC_SUPPORTED_INLINE_REFCNT_WITH_DEALLOC2MAIN) can generate +// a false positive that [super dealloc] is called twice if each object instance +// is not tracked separately by the checker. This test case is just a simple +// approximation to trigger the false positive. + +@class ClassWithOwnIvarInstanceClass; +@interface ClassWithOwnIvarInstanceClass : NSObject { + ClassWithOwnIvarInstanceClass *_ivar; + NSUInteger _retainCount; +} +@end + +@implementation ClassWithOwnIvarInstanceClass +- (instancetype)retain { + ++_retainCount; + return self; +} +- (oneway void)release { + --_retainCount; + if (!_retainCount) + [self dealloc]; +} +- (void)dealloc { + [_ivar release]; + [super dealloc]; // no warning: different instances of same class +} +@end + +//===------------------------------------------------------------------------=== +// Do not warn about calling [super dealloc] twice if +dealloc is a class +// method. + +@interface SuperDeallocClassMethodIgnoredClass : NSObject { } ++ (void)dealloc; +@end + +@implementation SuperDeallocClassMethodIgnoredClass ++ (void)dealloc { } +@end + +@interface SuperDeallocClassMethodIgnoredSubClass : NSObject { } ++ (void)dealloc; +@end + +@implementation SuperDeallocClassMethodIgnoredSubClass ++ (void)dealloc { + [super dealloc]; + [super dealloc]; // no warning: class method +} +@end + +//===------------------------------------------------------------------------=== +// Do not warn about calling [super dealloc] twice if when the analyzer has +// inlined the call to its super deallocator. + +@interface SuperClassCallingSuperDealloc : NSObject { + NSObject *_ivar; +} +@end + +@implementation SuperClassCallingSuperDealloc +- (void)dealloc; { + [_ivar release]; // no-warning + + [super dealloc]; +} +@end + +@interface SubclassCallingSuperDealloc : SuperClassCallingSuperDealloc +@end + +@implementation SubclassCallingSuperDealloc +- (void)dealloc; { + [super dealloc]; +} +@end + +//===------------------------------------------------------------------------=== +// Treat calling [super dealloc] twice as as a sink. + +@interface CallingSuperDeallocTwiceIsSink : NSObject +@end + +@implementation CallingSuperDeallocTwiceIsSink +- (void)dealloc; { + [super dealloc]; // expected-note {{[super dealloc] called here}} + [super dealloc]; // expected-warning {{[super dealloc] should not be called multiple times}} + // expected-note@-1 {{[super dealloc] should not be called multiple times}} + + clang_analyzer_warnIfReached(); // no-warning +} +@end + + +//===------------------------------------------------------------------------=== +// Test path notes with intervening method call on self. + +@interface InterveningMethodCallOnSelf : NSObject +@end + +@implementation InterveningMethodCallOnSelf +- (void)anotherMethod { +} + +- (void)dealloc; { + [super dealloc]; // expected-note {{[super dealloc] called here}} + [self anotherMethod]; // expected-warning {{Use of 'self' after it has been deallocated}} + // expected-note@-1 {{Use of 'self' after it has been deallocated}} + [super dealloc]; +} +@end