1 // RUN: %clang_analyze_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-output=text -verify %s 2 3 struct OSMetaClass; 4 5 #define OS_CONSUME __attribute__((os_consumed)) 6 #define OS_RETURNS_RETAINED __attribute__((os_returns_retained)) 7 #define OS_RETURNS_NOT_RETAINED __attribute__((os_returns_not_retained)) 8 9 #define OSTypeID(type) (type::metaClass) 10 11 #define OSDynamicCast(type, inst) \ 12 ((type *) OSMetaClassBase::safeMetaCast((inst), OSTypeID(type))) 13 14 using size_t = decltype(sizeof(int)); 15 16 struct OSObject { 17 virtual void retain(); 18 virtual void release() {}; 19 virtual void free(); 20 virtual ~OSObject(){} 21 22 unsigned int foo() { return 42; } 23 24 static OSObject *generateObject(int); 25 26 static OSObject *getObject(); 27 static OSObject *GetObject(); 28 29 30 static void * operator new(size_t size); 31 32 static const OSMetaClass * const metaClass; 33 }; 34 35 struct OSIterator : public OSObject { 36 37 static const OSMetaClass * const metaClass; 38 }; 39 40 struct OSArray : public OSObject { 41 unsigned int getCount(); 42 43 static OSArray *generateArrayHasCode() { 44 return new OSArray; 45 } 46 47 static OSArray *withCapacity(unsigned int capacity); 48 static void consumeArray(OS_CONSUME OSArray * array); 49 50 static OSArray* consumeArrayHasCode(OS_CONSUME OSArray * array) { 51 return nullptr; 52 } 53 54 OSIterator * getIterator(); 55 56 static OS_RETURNS_NOT_RETAINED OSArray *MaskedGetter(); 57 static OS_RETURNS_RETAINED OSArray *getOoopsActuallyCreate(); 58 59 static const OSMetaClass * const metaClass; 60 }; 61 62 struct OtherStruct { 63 static void doNothingToArray(OSArray *array); 64 OtherStruct(OSArray *arr); 65 }; 66 67 struct OSMetaClassBase { 68 static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta); 69 }; 70 71 void check_free_no_error() { 72 OSArray *arr = OSArray::withCapacity(10); 73 arr->retain(); 74 arr->retain(); 75 arr->retain(); 76 arr->free(); 77 } 78 79 void check_free_use_after_free() { 80 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}} 81 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}} 82 arr->free(); // expected-note{{Object released}} 83 arr->retain(); // expected-warning{{Reference-counted object is used after it is released}} 84 // expected-note@-1{{Reference-counted object is used after it is released}} 85 } 86 87 unsigned int check_leak_explicit_new() { 88 OSArray *arr = new OSArray; // expected-note{{Operator new returns an OSObject of type OSArray with a +1 retain count}} 89 return arr->getCount(); // expected-note{{Object leaked: allocated object of type OSArray is not referenced later in this execution path and has a retain count of +1}} 90 // expected-warning@-1{{Potential leak of an object of type OSArray}} 91 } 92 93 unsigned int check_leak_factory() { 94 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}} 95 return arr->getCount(); // expected-note{{Object leaked: object allocated and stored into 'arr' is not referenced later in this execution path and has a retain count of +1}} 96 // expected-warning@-1{{Potential leak of an object stored into 'arr'}} 97 } 98 99 void check_get_object() { 100 OSObject::getObject(); 101 } 102 103 void check_Get_object() { 104 OSObject::GetObject(); 105 } 106 107 void check_custom_iterator_rule(OSArray *arr) { 108 OSIterator *it = arr->getIterator(); 109 it->release(); 110 } 111 112 void check_iterator_leak(OSArray *arr) { 113 arr->getIterator(); // expected-note{{Call to method 'OSArray::getIterator' returns an OSObject of type OSIterator with a +1 retain count}} 114 } // expected-note{{Object leaked: allocated object of type OSIterator is not referenced later}} 115 // expected-warning@-1{{Potential leak of an object of type OSIterator}} 116 117 void check_no_invalidation() { 118 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}} 119 OtherStruct::doNothingToArray(arr); 120 } // expected-warning{{Potential leak of an object stored into 'arr'}} 121 // expected-note@-1{{Object leaked}} 122 123 void check_no_invalidation_other_struct() { 124 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}} 125 OtherStruct other(arr); // expected-warning{{Potential leak}} 126 // expected-note@-1{{Object leaked}} 127 } 128 129 struct ArrayOwner : public OSObject { 130 OSArray *arr; 131 ArrayOwner(OSArray *arr) : arr(arr) {} 132 133 static ArrayOwner* create(OSArray *arr) { 134 return new ArrayOwner(arr); 135 } 136 137 OSArray *getArray() { 138 return arr; 139 } 140 141 OSArray *createArray() { 142 return OSArray::withCapacity(10); 143 } 144 145 OSArray *createArraySourceUnknown(); 146 147 OSArray *getArraySourceUnknown(); 148 }; 149 150 OSArray *generateArray() { 151 return OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}} 152 // expected-note@-1{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}} 153 } 154 155 unsigned int check_leak_good_error_message() { 156 unsigned int out; 157 { 158 OSArray *leaked = generateArray(); // expected-note{{Calling 'generateArray'}} 159 // expected-note@-1{{Returning from 'generateArray'}} 160 out = leaked->getCount(); // expected-warning{{Potential leak of an object stored into 'leaked'}} 161 // 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}} 162 } 163 return out; 164 } 165 166 unsigned int check_leak_msg_temporary() { 167 return generateArray()->getCount(); // expected-warning{{Potential leak of an object}} 168 // expected-note@-1{{Calling 'generateArray'}} 169 // expected-note@-2{{Returning from 'generateArray'}} 170 // 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}} 171 } 172 173 void check_confusing_getters() { 174 OSArray *arr = OSArray::withCapacity(10); 175 176 ArrayOwner *AO = ArrayOwner::create(arr); 177 AO->getArray(); 178 179 AO->release(); 180 arr->release(); 181 } 182 183 void check_rc_consumed() { 184 OSArray *arr = OSArray::withCapacity(10); 185 OSArray::consumeArray(arr); 186 } 187 188 void check_rc_consume_temporary() { 189 OSArray::consumeArray(OSArray::withCapacity(10)); 190 } 191 192 void check_rc_getter() { 193 OSArray *arr = OSArray::MaskedGetter(); 194 (void)arr; 195 } 196 197 void check_rc_create() { 198 OSArray *arr = OSArray::getOoopsActuallyCreate(); 199 arr->release(); 200 } 201 202 203 void check_dynamic_cast() { 204 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); 205 arr->release(); 206 } 207 208 unsigned int check_dynamic_cast_no_null_on_orig(OSObject *obj) { 209 OSArray *arr = OSDynamicCast(OSArray, obj); 210 if (arr) { 211 return arr->getCount(); 212 } else { 213 214 // The fact that dynamic cast has failed should not imply that 215 // the input object was null. 216 return obj->foo(); // no-warning 217 } 218 } 219 220 void check_dynamic_cast_null_branch(OSObject *obj) { 221 OSArray *arr1 = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject}} 222 OSArray *arr = OSDynamicCast(OSArray, obj); 223 if (!arr) // expected-note{{Taking true branch}} 224 return; // expected-warning{{Potential leak of an object stored into 'arr1'}} 225 // expected-note@-1{{Object leaked}} 226 arr1->release(); 227 } 228 229 void check_dynamic_cast_null_check() { 230 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); // expected-note{{Call to method 'OSObject::generateObject' returns an OSObject}} 231 // expected-warning@-1{{Potential leak of an object}} 232 // expected-note@-2{{Object leaked}} 233 if (!arr) 234 return; 235 arr->release(); 236 } 237 238 void use_after_release() { 239 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}} 240 arr->release(); // expected-note{{Object released}} 241 arr->getCount(); // expected-warning{{Reference-counted object is used after it is released}} 242 // expected-note@-1{{Reference-counted object is used after it is released}} 243 } 244 245 void potential_leak() { 246 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}} 247 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}} 248 arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}} 249 arr->getCount(); 250 } // expected-warning{{Potential leak of an object stored into 'arr'}} 251 // 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}} 252 253 void proper_cleanup() { 254 OSArray *arr = OSArray::withCapacity(10); // +1 255 arr->retain(); // +2 256 arr->release(); // +1 257 arr->getCount(); 258 arr->release(); // 0 259 } 260 261 unsigned int no_warning_on_getter(ArrayOwner *owner) { 262 OSArray *arr = owner->getArray(); 263 return arr->getCount(); 264 } 265 266 unsigned int warn_on_overrelease(ArrayOwner *owner) { 267 // FIXME: summaries are not applied in case the source of the getter/setter 268 // is known. 269 // rdar://45681203 270 OSArray *arr = owner->getArray(); 271 arr->release(); 272 return arr->getCount(); 273 } 274 275 unsigned int nowarn_on_release_of_created(ArrayOwner *owner) { 276 OSArray *arr = owner->createArray(); 277 unsigned int out = arr->getCount(); 278 arr->release(); 279 return out; 280 } 281 282 unsigned int nowarn_on_release_of_created_source_unknown(ArrayOwner *owner) { 283 OSArray *arr = owner->createArraySourceUnknown(); 284 unsigned int out = arr->getCount(); 285 arr->release(); 286 return out; 287 } 288 289 unsigned int no_warn_ok_release(ArrayOwner *owner) { 290 OSArray *arr = owner->getArray(); // +0 291 arr->retain(); // +1 292 arr->release(); // +0 293 return arr->getCount(); // no-warning 294 } 295 296 unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) { 297 OSArray *arr = owner->getArraySourceUnknown(); // expected-note{{Call to method 'ArrayOwner::getArraySourceUnknown' returns an OSObject of type OSArray with a +0 retain count}} 298 arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} 299 // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} 300 return arr->getCount(); 301 } 302 303 unsigned int ok_release_with_unknown_source(ArrayOwner *owner) { 304 OSArray *arr = owner->getArraySourceUnknown(); // +0 305 arr->retain(); // +1 306 arr->release(); // +0 307 return arr->getCount(); 308 } 309