1 // RUN: %clang_analyze_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-config osx.cocoa.RetainCount:CheckOSObject=true -analyzer-output=text -verify %s 2 3 struct OSMetaClass; 4 5 #define TRUSTED __attribute__((annotate("rc_ownership_trusted_implementation"))) 6 #define OS_CONSUME TRUSTED __attribute__((annotate("rc_ownership_consumed"))) 7 #define OS_RETURNS_RETAINED TRUSTED __attribute__((annotate("rc_ownership_returns_retained"))) 8 #define OS_RETURNS_NOT_RETAINED TRUSTED __attribute__((annotate("rc_ownership_returns_not_retained"))) 9 10 #define OSTypeID(type) (type::metaClass) 11 12 #define OSDynamicCast(type, inst) \ 13 ((type *) OSMetaClassBase::safeMetaCast((inst), OSTypeID(type))) 14 15 struct OSObject { 16 virtual void retain(); 17 virtual void release() {}; 18 virtual ~OSObject(){} 19 20 static OSObject *generateObject(int); 21 22 static const OSMetaClass * const metaClass; 23 }; 24 25 struct OSArray : public OSObject { 26 unsigned int getCount(); 27 28 static OSArray *withCapacity(unsigned int capacity); 29 static void consumeArray(OS_CONSUME OSArray * array); 30 31 static OSArray* consumeArrayHasCode(OS_CONSUME OSArray * array) { 32 return nullptr; 33 } 34 35 static OS_RETURNS_NOT_RETAINED OSArray *MaskedGetter(); 36 static OS_RETURNS_RETAINED OSArray *getOoopsActuallyCreate(); 37 38 39 static const OSMetaClass * const metaClass; 40 }; 41 42 struct OtherStruct { 43 static void doNothingToArray(OSArray *array); 44 }; 45 46 struct OSMetaClassBase { 47 static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta); 48 }; 49 50 void check_no_invalidation() { 51 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}} 52 OtherStruct::doNothingToArray(arr); 53 } // expected-warning{{Potential leak of an object stored into 'arr'}} 54 // expected-note@-1{{Object leaked}} 55 56 void check_rc_consumed() { 57 OSArray *arr = OSArray::withCapacity(10); 58 OSArray::consumeArray(arr); 59 } 60 61 void check_rc_consume_temporary() { 62 OSArray::consumeArray(OSArray::withCapacity(10)); 63 } 64 65 void check_rc_getter() { 66 OSArray *arr = OSArray::MaskedGetter(); 67 (void)arr; 68 } 69 70 void check_rc_create() { 71 OSArray *arr = OSArray::getOoopsActuallyCreate(); 72 arr->release(); 73 } 74 75 76 void check_dynamic_cast() { 77 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); 78 arr->release(); 79 } 80 81 void check_dynamic_cast_null_check() { 82 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); 83 if (!arr) 84 return; 85 arr->release(); 86 } 87 88 void use_after_release() { 89 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}} 90 arr->release(); // expected-note{{Object released}} 91 arr->getCount(); // expected-warning{{Reference-counted object is used after it is released}} 92 // expected-note@-1{{Reference-counted object is used after it is released}} 93 } 94 95 void potential_leak() { 96 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}} 97 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}} 98 arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}} 99 arr->getCount(); 100 } // expected-warning{{Potential leak of an object stored into 'arr'}} 101 // 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}} 102 103 void proper_cleanup() { 104 OSArray *arr = OSArray::withCapacity(10); // +1 105 arr->retain(); // +2 106 arr->release(); // +1 107 arr->getCount(); 108 arr->release(); // 0 109 } 110 111 struct ArrayOwner { 112 OSArray *arr; 113 114 OSArray *getArray() { 115 return arr; 116 } 117 118 OSArray *createArray() { 119 return OSArray::withCapacity(10); 120 } 121 122 OSArray *createArraySourceUnknown(); 123 124 OSArray *getArraySourceUnknown(); 125 }; 126 127 unsigned int no_warning_on_getter(ArrayOwner *owner) { 128 OSArray *arr = owner->getArray(); 129 return arr->getCount(); 130 } 131 132 unsigned int warn_on_overrelease(ArrayOwner *owner) { 133 OSArray *arr = owner->getArray(); // expected-note{{function call returns an OSObject of type struct OSArray * with a +0 retain count}} 134 arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} 135 // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} 136 return arr->getCount(); 137 } 138 139 unsigned int nowarn_on_release_of_created(ArrayOwner *owner) { 140 OSArray *arr = owner->createArray(); 141 unsigned int out = arr->getCount(); 142 arr->release(); 143 return out; 144 } 145 146 unsigned int nowarn_on_release_of_created_source_unknown(ArrayOwner *owner) { 147 OSArray *arr = owner->createArraySourceUnknown(); 148 unsigned int out = arr->getCount(); 149 arr->release(); 150 return out; 151 } 152 153 unsigned int no_warn_ok_release(ArrayOwner *owner) { 154 OSArray *arr = owner->getArray(); // +0 155 arr->retain(); // +1 156 arr->release(); // +0 157 return arr->getCount(); // no-warning 158 } 159 160 unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) { 161 OSArray *arr = owner->getArraySourceUnknown(); // expected-note{{function call returns an OSObject of type struct OSArray * with a +0 retain count}} 162 arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} 163 // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} 164 return arr->getCount(); 165 } 166 167 unsigned int ok_release_with_unknown_source(ArrayOwner *owner) { 168 OSArray *arr = owner->getArraySourceUnknown(); // +0 169 arr->retain(); // +1 170 arr->release(); // +0 171 return arr->getCount(); 172 } 173