1 // RUN: %clang_analyze_cc1 -analyze -analyzer-checker=core,osx -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 #define OS_CONSUMES_THIS __attribute__((os_consumes_this)) 9 10 #define OSTypeID(type) (type::metaClass) 11 12 #define OSDynamicCast(type, inst) \ 13 ((type *) OSMetaClassBase::safeMetaCast((inst), OSTypeID(type))) 14 15 using size_t = decltype(sizeof(int)); 16 17 struct OSObject { 18 virtual void retain(); 19 virtual void release() {}; 20 virtual void free(); 21 virtual ~OSObject(){} 22 23 unsigned int foo() { return 42; } 24 25 virtual OS_RETURNS_NOT_RETAINED OSObject *identity(); 26 27 static OSObject *generateObject(int); 28 29 static OSObject *getObject(); 30 static OSObject *GetObject(); 31 32 static void * operator new(size_t size); 33 34 static const OSMetaClass * const metaClass; 35 }; 36 37 struct OSIterator : public OSObject { 38 39 static const OSMetaClass * const metaClass; 40 }; 41 42 struct OSArray : public OSObject { 43 unsigned int getCount(); 44 45 OSIterator * getIterator(); 46 47 OSObject *identity() override; 48 49 virtual OSObject *generateObject(OSObject *input); 50 51 virtual void consumeReference(OS_CONSUME OSArray *other); 52 53 void putIntoArray(OSArray *array) OS_CONSUMES_THIS; 54 55 template <typename T> 56 void putIntoT(T *owner) OS_CONSUMES_THIS; 57 58 static OSArray *generateArrayHasCode() { 59 return new OSArray; 60 } 61 62 static OSArray *withCapacity(unsigned int capacity); 63 static void consumeArray(OS_CONSUME OSArray * array); 64 65 static OSArray* consumeArrayHasCode(OS_CONSUME OSArray * array) { 66 return nullptr; 67 } 68 69 static OS_RETURNS_NOT_RETAINED OSArray *MaskedGetter(); 70 static OS_RETURNS_RETAINED OSArray *getOoopsActuallyCreate(); 71 72 static const OSMetaClass * const metaClass; 73 }; 74 75 struct MyArray : public OSArray { 76 void consumeReference(OSArray *other) override; 77 78 OSObject *identity() override; 79 80 OSObject *generateObject(OSObject *input) override; 81 }; 82 83 struct OtherStruct { 84 static void doNothingToArray(OSArray *array); 85 OtherStruct(OSArray *arr); 86 }; 87 88 struct OSMetaClassBase { 89 static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta); 90 }; 91 92 void escape(void *); 93 bool coin(); 94 95 bool os_consume_violation(OS_CONSUME OSObject *obj) { 96 if (coin()) { // expected-note{{Assuming the condition is false}} 97 // expected-note@-1{{Taking false branch}} 98 escape(obj); 99 return true; 100 } 101 return false; // expected-note{{Parameter 'obj' is marked as consuming, but the function does not consume the reference}} 102 } 103 104 void os_consume_ok(OS_CONSUME OSObject *obj) { 105 escape(obj); 106 } 107 108 void use_os_consume_violation() { 109 OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type OSObject with a +1 retain count}} 110 os_consume_violation(obj); // expected-note{{Calling 'os_consume_violation'}} 111 // expected-note@-1{{Returning from 'os_consume_violation'}} 112 } // expected-note{{Object leaked: object allocated and stored into 'obj' is not referenced later in this execution path and has a retain count of +1}} 113 // expected-warning@-1{{Potential leak of an object stored into 'obj'}} 114 115 void use_os_consume_ok() { 116 OSObject *obj = new OSObject; 117 os_consume_ok(obj); 118 } 119 120 void test_escaping_into_voidstar() { 121 OSObject *obj = new OSObject; 122 escape(obj); 123 } 124 125 void test_no_infinite_check_recursion(MyArray *arr) { 126 OSObject *input = new OSObject; 127 OSObject *o = arr->generateObject(input); 128 o->release(); 129 input->release(); 130 } 131 132 133 void check_param_attribute_propagation(MyArray *parent) { 134 OSArray *arr = new OSArray; 135 parent->consumeReference(arr); 136 } 137 138 unsigned int check_attribute_propagation(OSArray *arr) { 139 OSObject *other = arr->identity(); 140 OSArray *casted = OSDynamicCast(OSArray, other); 141 if (casted) 142 return casted->getCount(); 143 return 0; 144 } 145 146 unsigned int check_attribute_indirect_propagation(MyArray *arr) { 147 OSObject *other = arr->identity(); 148 OSArray *casted = OSDynamicCast(OSArray, other); 149 if (casted) 150 return casted->getCount(); 151 return 0; 152 } 153 154 void check_consumes_this(OSArray *owner) { 155 OSArray *arr = new OSArray; 156 arr->putIntoArray(owner); 157 } 158 159 void check_consumes_this_with_template(OSArray *owner) { 160 OSArray *arr = new OSArray; 161 arr->putIntoT(owner); 162 } 163 164 void check_free_no_error() { 165 OSArray *arr = OSArray::withCapacity(10); 166 arr->retain(); 167 arr->retain(); 168 arr->retain(); 169 arr->free(); 170 } 171 172 void check_free_use_after_free() { 173 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}} 174 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}} 175 arr->free(); // expected-note{{Object released}} 176 arr->retain(); // expected-warning{{Reference-counted object is used after it is released}} 177 // expected-note@-1{{Reference-counted object is used after it is released}} 178 } 179 180 unsigned int check_leak_explicit_new() { 181 OSArray *arr = new OSArray; // expected-note{{Operator 'new' returns an OSObject of type OSArray with a +1 retain count}} 182 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}} 183 // expected-warning@-1{{Potential leak of an object stored into 'arr'}} 184 } 185 186 unsigned int check_leak_factory() { 187 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}} 188 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}} 189 // expected-warning@-1{{Potential leak of an object stored into 'arr'}} 190 } 191 192 void check_get_object() { 193 OSObject::getObject(); 194 } 195 196 void check_Get_object() { 197 OSObject::GetObject(); 198 } 199 200 void check_custom_iterator_rule(OSArray *arr) { 201 OSIterator *it = arr->getIterator(); 202 it->release(); 203 } 204 205 void check_iterator_leak(OSArray *arr) { 206 arr->getIterator(); // expected-note{{Call to method 'OSArray::getIterator' returns an OSObject of type OSIterator with a +1 retain count}} 207 } // expected-note{{Object leaked: allocated object of type OSIterator is not referenced later}} 208 // expected-warning@-1{{Potential leak of an object of type OSIterator}} 209 210 void check_no_invalidation() { 211 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}} 212 OtherStruct::doNothingToArray(arr); 213 } // expected-warning{{Potential leak of an object stored into 'arr'}} 214 // expected-note@-1{{Object leaked}} 215 216 void check_no_invalidation_other_struct() { 217 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}} 218 OtherStruct other(arr); // expected-warning{{Potential leak}} 219 // expected-note@-1{{Object leaked}} 220 } 221 222 struct ArrayOwner : public OSObject { 223 OSArray *arr; 224 ArrayOwner(OSArray *arr) : arr(arr) {} 225 226 static ArrayOwner* create(OSArray *arr) { 227 return new ArrayOwner(arr); 228 } 229 230 OSArray *getArray() { 231 return arr; 232 } 233 234 OSArray *createArray() { 235 return OSArray::withCapacity(10); 236 } 237 238 OSArray *createArraySourceUnknown(); 239 240 OSArray *getArraySourceUnknown(); 241 }; 242 243 OSArray *generateArray() { 244 return OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}} 245 // expected-note@-1{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}} 246 } 247 248 unsigned int check_leak_good_error_message() { 249 unsigned int out; 250 { 251 OSArray *leaked = generateArray(); // expected-note{{Calling 'generateArray'}} 252 // expected-note@-1{{Returning from 'generateArray'}} 253 out = leaked->getCount(); // expected-warning{{Potential leak of an object stored into 'leaked'}} 254 // 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}} 255 } 256 return out; 257 } 258 259 unsigned int check_leak_msg_temporary() { 260 return generateArray()->getCount(); // expected-warning{{Potential leak of an object}} 261 // expected-note@-1{{Calling 'generateArray'}} 262 // expected-note@-2{{Returning from 'generateArray'}} 263 // 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}} 264 } 265 266 void check_confusing_getters() { 267 OSArray *arr = OSArray::withCapacity(10); 268 269 ArrayOwner *AO = ArrayOwner::create(arr); 270 AO->getArray(); 271 272 AO->release(); 273 arr->release(); 274 } 275 276 void check_rc_consumed() { 277 OSArray *arr = OSArray::withCapacity(10); 278 OSArray::consumeArray(arr); 279 } 280 281 void check_rc_consume_temporary() { 282 OSArray::consumeArray(OSArray::withCapacity(10)); 283 } 284 285 void check_rc_getter() { 286 OSArray *arr = OSArray::MaskedGetter(); 287 (void)arr; 288 } 289 290 void check_rc_create() { 291 OSArray *arr = OSArray::getOoopsActuallyCreate(); 292 arr->release(); 293 } 294 295 296 void check_dynamic_cast() { 297 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); 298 arr->release(); 299 } 300 301 unsigned int check_dynamic_cast_no_null_on_orig(OSObject *obj) { 302 OSArray *arr = OSDynamicCast(OSArray, obj); 303 if (arr) { 304 return arr->getCount(); 305 } else { 306 307 // The fact that dynamic cast has failed should not imply that 308 // the input object was null. 309 return obj->foo(); // no-warning 310 } 311 } 312 313 void check_dynamic_cast_null_branch(OSObject *obj) { 314 OSArray *arr1 = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject}} 315 OSArray *arr = OSDynamicCast(OSArray, obj); 316 if (!arr) // expected-note{{Taking true branch}} 317 return; // expected-warning{{Potential leak of an object stored into 'arr1'}} 318 // expected-note@-1{{Object leaked}} 319 arr1->release(); 320 } 321 322 void check_dynamic_cast_null_check() { 323 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); // expected-note{{Call to method 'OSObject::generateObject' returns an OSObject}} 324 // expected-warning@-1{{Potential leak of an object}} 325 // expected-note@-2{{Object leaked}} 326 if (!arr) 327 return; 328 arr->release(); 329 } 330 331 void use_after_release() { 332 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}} 333 arr->release(); // expected-note{{Object released}} 334 arr->getCount(); // expected-warning{{Reference-counted object is used after it is released}} 335 // expected-note@-1{{Reference-counted object is used after it is released}} 336 } 337 338 void potential_leak() { 339 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}} 340 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}} 341 arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}} 342 arr->getCount(); 343 } // expected-warning{{Potential leak of an object stored into 'arr'}} 344 // 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}} 345 346 void proper_cleanup() { 347 OSArray *arr = OSArray::withCapacity(10); // +1 348 arr->retain(); // +2 349 arr->release(); // +1 350 arr->getCount(); 351 arr->release(); // 0 352 } 353 354 unsigned int no_warning_on_getter(ArrayOwner *owner) { 355 OSArray *arr = owner->getArray(); 356 return arr->getCount(); 357 } 358 359 unsigned int warn_on_overrelease(ArrayOwner *owner) { 360 // FIXME: summaries are not applied in case the source of the getter/setter 361 // is known. 362 // rdar://45681203 363 OSArray *arr = owner->getArray(); 364 arr->release(); 365 return arr->getCount(); 366 } 367 368 unsigned int nowarn_on_release_of_created(ArrayOwner *owner) { 369 OSArray *arr = owner->createArray(); 370 unsigned int out = arr->getCount(); 371 arr->release(); 372 return out; 373 } 374 375 unsigned int nowarn_on_release_of_created_source_unknown(ArrayOwner *owner) { 376 OSArray *arr = owner->createArraySourceUnknown(); 377 unsigned int out = arr->getCount(); 378 arr->release(); 379 return out; 380 } 381 382 unsigned int no_warn_ok_release(ArrayOwner *owner) { 383 OSArray *arr = owner->getArray(); // +0 384 arr->retain(); // +1 385 arr->release(); // +0 386 return arr->getCount(); // no-warning 387 } 388 389 unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) { 390 OSArray *arr = owner->getArraySourceUnknown(); // expected-note{{Call to method 'ArrayOwner::getArraySourceUnknown' returns an OSObject of type OSArray with a +0 retain count}} 391 arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} 392 // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} 393 return arr->getCount(); 394 } 395 396 unsigned int ok_release_with_unknown_source(ArrayOwner *owner) { 397 OSArray *arr = owner->getArraySourceUnknown(); // +0 398 arr->retain(); // +1 399 arr->release(); // +0 400 return arr->getCount(); 401 } 402