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