2018-11-01 01:38:12 +08:00
// RUN: %clang_analyze_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-output=text -verify %s
2018-08-23 08:26:59 +08:00
2018-10-12 06:59:16 +08:00
struct OSMetaClass ;
2018-11-01 01:38:29 +08:00
# define OS_CONSUME __attribute__((annotate("rc_ownership_consumed")))
# define OS_RETURNS_RETAINED __attribute__((annotate("rc_ownership_returns_retained")))
# define OS_RETURNS_NOT_RETAINED __attribute__((annotate("rc_ownership_returns_not_retained")))
2018-10-24 07:11:50 +08:00
2018-10-12 06:59:16 +08:00
# define OSTypeID(type) (type::metaClass)
# define OSDynamicCast(type, inst) \
( ( type * ) OSMetaClassBase : : safeMetaCast ( ( inst ) , OSTypeID ( type ) ) )
2018-08-23 08:26:59 +08:00
struct OSObject {
virtual void retain ( ) ;
2018-10-24 07:11:30 +08:00
virtual void release ( ) { } ;
2018-08-23 08:26:59 +08:00
virtual ~ OSObject ( ) { }
2018-10-12 06:59:16 +08:00
2018-10-26 07:38:07 +08:00
unsigned int foo ( ) { return 42 ; }
2018-10-12 06:59:16 +08:00
static OSObject * generateObject ( int ) ;
2018-11-30 10:18:10 +08:00
static OSObject * getObject ( ) ;
static OSObject * GetObject ( ) ;
2018-10-12 06:59:16 +08:00
static const OSMetaClass * const metaClass ;
2018-08-23 08:26:59 +08:00
} ;
2018-11-01 01:38:46 +08:00
struct OSIterator : public OSObject {
2018-11-30 10:17:31 +08:00
static const OSMetaClass * const metaClass ;
2018-11-01 01:38:46 +08:00
} ;
2018-08-23 08:26:59 +08:00
struct OSArray : public OSObject {
unsigned int getCount ( ) ;
static OSArray * withCapacity ( unsigned int capacity ) ;
2018-10-24 07:11:50 +08:00
static void consumeArray ( OS_CONSUME OSArray * array ) ;
static OSArray * consumeArrayHasCode ( OS_CONSUME OSArray * array ) {
return nullptr ;
}
2018-11-01 01:38:46 +08:00
OSIterator * getIterator ( ) ;
2018-10-24 07:11:50 +08:00
static OS_RETURNS_NOT_RETAINED OSArray * MaskedGetter ( ) ;
static OS_RETURNS_RETAINED OSArray * getOoopsActuallyCreate ( ) ;
2018-10-12 06:59:16 +08:00
static const OSMetaClass * const metaClass ;
} ;
2018-10-24 07:11:50 +08:00
struct OtherStruct {
static void doNothingToArray ( OSArray * array ) ;
2018-10-26 07:38:41 +08:00
OtherStruct ( OSArray * arr ) ;
2018-10-24 07:11:50 +08:00
} ;
2018-10-12 06:59:16 +08:00
struct OSMetaClassBase {
static OSObject * safeMetaCast ( const OSObject * inst , const OSMetaClass * meta ) ;
2018-08-23 08:26:59 +08:00
} ;
2018-11-30 10:18:10 +08:00
void check_get_object ( ) {
OSObject : : getObject ( ) ;
}
void check_Get_object ( ) {
OSObject : : GetObject ( ) ;
}
2018-11-01 01:38:46 +08:00
void check_custom_iterator_rule ( OSArray * arr ) {
OSIterator * it = arr - > getIterator ( ) ;
it - > release ( ) ;
}
2018-11-30 10:17:57 +08:00
void check_iterator_leak ( OSArray * arr ) {
arr - > getIterator ( ) ; // expected-note{{Call to method 'OSArray::getIterator' returns an OSObject of type struct OSIterator * with a +1 retain count}}
} // expected-note{{Object leaked: allocated object of type struct OSIterator * is not referenced later}}
// expected-warning@-1{{Potential leak of an object of type struct OSIterator *}}n this execution path and has a retain count of +1}}
2018-10-24 07:11:50 +08:00
void check_no_invalidation ( ) {
2018-11-30 10:17:57 +08:00
OSArray * arr = OSArray : : withCapacity ( 10 ) ; // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
2018-10-24 07:11:50 +08:00
OtherStruct : : doNothingToArray ( arr ) ;
} // expected-warning{{Potential leak of an object stored into 'arr'}}
// expected-note@-1{{Object leaked}}
2018-10-26 07:38:41 +08:00
void check_no_invalidation_other_struct ( ) {
2018-11-30 10:17:57 +08:00
OSArray * arr = OSArray : : withCapacity ( 10 ) ; // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
2018-10-26 07:38:41 +08:00
OtherStruct other ( arr ) ; // expected-warning{{Potential leak}}
// expected-note@-1{{Object leaked}}
}
2018-11-01 01:38:29 +08:00
struct ArrayOwner : public OSObject {
OSArray * arr ;
ArrayOwner ( OSArray * arr ) : arr ( arr ) { }
static ArrayOwner * create ( OSArray * arr ) {
return new ArrayOwner ( arr ) ;
}
OSArray * getArray ( ) {
return arr ;
}
OSArray * createArray ( ) {
return OSArray : : withCapacity ( 10 ) ;
}
OSArray * createArraySourceUnknown ( ) ;
OSArray * getArraySourceUnknown ( ) ;
} ;
2018-11-30 10:17:31 +08:00
OSArray * generateArray ( ) {
2018-11-30 10:17:57 +08:00
return OSArray : : withCapacity ( 10 ) ; // expected-note{{Call to method 'withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
// expected-note@-1{{Call to method 'withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
2018-11-30 10:17:31 +08:00
}
unsigned int check_leak_good_error_message ( ) {
unsigned int out ;
{
OSArray * leaked = generateArray ( ) ; // expected-note{{Calling 'generateArray'}}
// expected-note@-1{{Returning from 'generateArray'}}
out = leaked - > getCount ( ) ; // expected-warning{{Potential leak of an object stored into 'leaked'}}
// expected-note@-1{{Object leaked: object allocated and stored into 'leaked' is not referenced later in this execution path and has a retain count of +1}}
}
return out ;
}
unsigned int check_leak_msg_temporary ( ) {
2018-11-30 10:17:44 +08:00
return generateArray ( ) - > getCount ( ) ; // expected-warning{{Potential leak of an object}}
// expected-note@-1{{Calling 'generateArray'}}
// expected-note@-2{{Returning from 'generateArray'}}
// expected-note@-3{{Object leaked: allocated object of type OSArray is not referenced later in this execution path and has a retain count of +1}}
2018-11-30 10:17:31 +08:00
}
2018-11-01 01:38:29 +08:00
void check_confusing_getters ( ) {
OSArray * arr = OSArray : : withCapacity ( 10 ) ;
ArrayOwner * AO = ArrayOwner : : create ( arr ) ;
AO - > getArray ( ) ;
AO - > release ( ) ;
arr - > release ( ) ;
}
2018-10-24 07:11:50 +08:00
void check_rc_consumed ( ) {
OSArray * arr = OSArray : : withCapacity ( 10 ) ;
OSArray : : consumeArray ( arr ) ;
}
void check_rc_consume_temporary ( ) {
OSArray : : consumeArray ( OSArray : : withCapacity ( 10 ) ) ;
}
void check_rc_getter ( ) {
OSArray * arr = OSArray : : MaskedGetter ( ) ;
( void ) arr ;
}
void check_rc_create ( ) {
OSArray * arr = OSArray : : getOoopsActuallyCreate ( ) ;
arr - > release ( ) ;
}
2018-10-12 06:59:16 +08:00
void check_dynamic_cast ( ) {
OSArray * arr = OSDynamicCast ( OSArray , OSObject : : generateObject ( 1 ) ) ;
arr - > release ( ) ;
}
2018-10-26 07:38:07 +08:00
unsigned int check_dynamic_cast_no_null_on_orig ( OSObject * obj ) {
OSArray * arr = OSDynamicCast ( OSArray , obj ) ;
if ( arr ) {
return arr - > getCount ( ) ;
} else {
// The fact that dynamic cast has failed should not imply that
// the input object was null.
return obj - > foo ( ) ; // no-warning
}
}
void check_dynamic_cast_null_branch ( OSObject * obj ) {
2018-11-30 10:17:57 +08:00
OSArray * arr1 = OSArray : : withCapacity ( 10 ) ; // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject}}
2018-10-26 07:38:07 +08:00
OSArray * arr = OSDynamicCast ( OSArray , obj ) ;
if ( ! arr ) // expected-note{{Taking true branch}}
2018-11-30 10:17:31 +08:00
return ; // expected-warning{{Potential leak of an object stored into 'arr1'}}
2018-10-26 07:38:07 +08:00
// expected-note@-1{{Object leaked}}
arr1 - > release ( ) ;
}
2018-10-12 06:59:16 +08:00
void check_dynamic_cast_null_check ( ) {
2018-11-30 10:17:57 +08:00
OSArray * arr = OSDynamicCast ( OSArray , OSObject : : generateObject ( 1 ) ) ; // expected-note{{Call to method 'OSObject::generateObject' returns an OSObject}}
2018-10-26 07:38:07 +08:00
// expected-warning@-1{{Potential leak of an object}}
// expected-note@-2{{Object leaked}}
2018-10-12 06:59:16 +08:00
if ( ! arr )
return ;
arr - > release ( ) ;
}
2018-08-23 08:26:59 +08:00
void use_after_release ( ) {
2018-11-30 10:17:57 +08:00
OSArray * arr = OSArray : : withCapacity ( 10 ) ; // expected-note{{Call to method 'withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
2018-08-23 08:26:59 +08:00
arr - > release ( ) ; // expected-note{{Object released}}
arr - > getCount ( ) ; // expected-warning{{Reference-counted object is used after it is released}}
// expected-note@-1{{Reference-counted object is used after it is released}}
}
void potential_leak ( ) {
2018-11-30 10:17:57 +08:00
OSArray * arr = OSArray : : withCapacity ( 10 ) ; // expected-note{{Call to method 'withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
2018-08-23 08:26:59 +08:00
arr - > retain ( ) ; // expected-note{{Reference count incremented. The object now has a +2 retain count}}
arr - > release ( ) ; // expected-note{{Reference count decremented. The object now has a +1 retain count}}
arr - > getCount ( ) ;
} // expected-warning{{Potential leak of an object stored into 'arr'}}
// expected-note@-1{{Object leaked: object allocated and stored into 'arr' is not referenced later in this execution path and has a retain count of +1}}
void proper_cleanup ( ) {
OSArray * arr = OSArray : : withCapacity ( 10 ) ; // +1
arr - > retain ( ) ; // +2
arr - > release ( ) ; // +1
arr - > getCount ( ) ;
arr - > release ( ) ; // 0
}
unsigned int no_warning_on_getter ( ArrayOwner * owner ) {
OSArray * arr = owner - > getArray ( ) ;
return arr - > getCount ( ) ;
}
unsigned int warn_on_overrelease ( ArrayOwner * owner ) {
2018-11-01 01:38:29 +08:00
// FIXME: summaries are not applied in case the source of the getter/setter
// is known.
// rdar://45681203
OSArray * arr = owner - > getArray ( ) ;
arr - > release ( ) ;
2018-08-23 08:26:59 +08:00
return arr - > getCount ( ) ;
}
unsigned int nowarn_on_release_of_created ( ArrayOwner * owner ) {
OSArray * arr = owner - > createArray ( ) ;
unsigned int out = arr - > getCount ( ) ;
arr - > release ( ) ;
return out ;
}
unsigned int nowarn_on_release_of_created_source_unknown ( ArrayOwner * owner ) {
OSArray * arr = owner - > createArraySourceUnknown ( ) ;
unsigned int out = arr - > getCount ( ) ;
arr - > release ( ) ;
return out ;
}
unsigned int no_warn_ok_release ( ArrayOwner * owner ) {
OSArray * arr = owner - > getArray ( ) ; // +0
arr - > retain ( ) ; // +1
arr - > release ( ) ; // +0
return arr - > getCount ( ) ; // no-warning
}
unsigned int warn_on_overrelease_with_unknown_source ( ArrayOwner * owner ) {
2018-11-30 10:17:57 +08:00
OSArray * arr = owner - > getArraySourceUnknown ( ) ; // expected-note{{Call to method 'ArrayOwner::getArraySourceUnknown' returns an OSObject of type OSArray with a +0 retain count}}
2018-08-23 08:26:59 +08:00
arr - > release ( ) ; // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
// expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
return arr - > getCount ( ) ;
}
unsigned int ok_release_with_unknown_source ( ArrayOwner * owner ) {
OSArray * arr = owner - > getArraySourceUnknown ( ) ; // +0
arr - > retain ( ) ; // +1
arr - > release ( ) ; // +0
return arr - > getCount ( ) ;
}