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