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 OSObject { 4 virtual void retain(); 5 virtual void release(); 6 7 virtual ~OSObject(){} 8 }; 9 10 struct OSArray : public OSObject { 11 unsigned int getCount(); 12 13 static OSArray *withCapacity(unsigned int capacity); 14 }; 15 16 void use_after_release() { 17 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}} 18 arr->release(); // expected-note{{Object released}} 19 arr->getCount(); // expected-warning{{Reference-counted object is used after it is released}} 20 // expected-note@-1{{Reference-counted object is used after it is released}} 21 } 22 23 void potential_leak() { 24 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}} 25 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}} 26 arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}} 27 arr->getCount(); 28 } // expected-warning{{Potential leak of an object stored into 'arr'}} 29 // 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}} 30 31 void proper_cleanup() { 32 OSArray *arr = OSArray::withCapacity(10); // +1 33 arr->retain(); // +2 34 arr->release(); // +1 35 arr->getCount(); 36 arr->release(); // 0 37 } 38 39 struct ArrayOwner { 40 OSArray *arr; 41 42 OSArray *getArray() { 43 return arr; 44 } 45 46 OSArray *createArray() { 47 return OSArray::withCapacity(10); 48 } 49 50 OSArray *createArraySourceUnknown(); 51 52 OSArray *getArraySourceUnknown(); 53 }; 54 55 //unsigned int leak_on_create_no_release(ArrayOwner *owner) { 56 //OSArray *myArray = 57 58 //} 59 60 unsigned int no_warning_on_getter(ArrayOwner *owner) { 61 OSArray *arr = owner->getArray(); 62 return arr->getCount(); 63 } 64 65 unsigned int warn_on_overrelease(ArrayOwner *owner) { 66 OSArray *arr = owner->getArray(); // expected-note{{function call returns an OSObject of type struct OSArray * with a +0 retain count}} 67 arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} 68 // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} 69 return arr->getCount(); 70 } 71 72 unsigned int nowarn_on_release_of_created(ArrayOwner *owner) { 73 OSArray *arr = owner->createArray(); 74 unsigned int out = arr->getCount(); 75 arr->release(); 76 return out; 77 } 78 79 unsigned int nowarn_on_release_of_created_source_unknown(ArrayOwner *owner) { 80 OSArray *arr = owner->createArraySourceUnknown(); 81 unsigned int out = arr->getCount(); 82 arr->release(); 83 return out; 84 } 85 86 unsigned int no_warn_ok_release(ArrayOwner *owner) { 87 OSArray *arr = owner->getArray(); // +0 88 arr->retain(); // +1 89 arr->release(); // +0 90 return arr->getCount(); // no-warning 91 } 92 93 unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) { 94 OSArray *arr = owner->getArraySourceUnknown(); // expected-note{{function call returns an OSObject of type struct OSArray * with a +0 retain count}} 95 arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} 96 // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} 97 return arr->getCount(); 98 } 99 100 unsigned int ok_release_with_unknown_source(ArrayOwner *owner) { 101 OSArray *arr = owner->getArraySourceUnknown(); // +0 102 arr->retain(); // +1 103 arr->release(); // +0 104 return arr->getCount(); 105 } 106