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 unsigned int foo() { return 42; } 21 22 static OSObject *generateObject(int); 23 24 static const OSMetaClass * const metaClass; 25 }; 26 27 struct OSArray : public OSObject { 28 unsigned int getCount(); 29 30 static OSArray *withCapacity(unsigned int capacity); 31 static void consumeArray(OS_CONSUME OSArray * array); 32 33 static OSArray* consumeArrayHasCode(OS_CONSUME OSArray * array) { 34 return nullptr; 35 } 36 37 static OS_RETURNS_NOT_RETAINED OSArray *MaskedGetter(); 38 static OS_RETURNS_RETAINED OSArray *getOoopsActuallyCreate(); 39 40 41 static const OSMetaClass * const metaClass; 42 }; 43 44 struct OtherStruct { 45 static void doNothingToArray(OSArray *array); 46 OtherStruct(OSArray *arr); 47 }; 48 49 struct OSMetaClassBase { 50 static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta); 51 }; 52 53 void check_no_invalidation() { 54 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}} 55 OtherStruct::doNothingToArray(arr); 56 } // expected-warning{{Potential leak of an object stored into 'arr'}} 57 // expected-note@-1{{Object leaked}} 58 59 void check_no_invalidation_other_struct() { 60 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}} 61 OtherStruct other(arr); // expected-warning{{Potential leak}} 62 // expected-note@-1{{Object leaked}} 63 } 64 65 void check_rc_consumed() { 66 OSArray *arr = OSArray::withCapacity(10); 67 OSArray::consumeArray(arr); 68 } 69 70 void check_rc_consume_temporary() { 71 OSArray::consumeArray(OSArray::withCapacity(10)); 72 } 73 74 void check_rc_getter() { 75 OSArray *arr = OSArray::MaskedGetter(); 76 (void)arr; 77 } 78 79 void check_rc_create() { 80 OSArray *arr = OSArray::getOoopsActuallyCreate(); 81 arr->release(); 82 } 83 84 85 void check_dynamic_cast() { 86 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); 87 arr->release(); 88 } 89 90 unsigned int check_dynamic_cast_no_null_on_orig(OSObject *obj) { 91 OSArray *arr = OSDynamicCast(OSArray, obj); 92 if (arr) { 93 return arr->getCount(); 94 } else { 95 96 // The fact that dynamic cast has failed should not imply that 97 // the input object was null. 98 return obj->foo(); // no-warning 99 } 100 } 101 102 void check_dynamic_cast_null_branch(OSObject *obj) { 103 OSArray *arr1 = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject}} 104 OSArray *arr = OSDynamicCast(OSArray, obj); 105 if (!arr) // expected-note{{Taking true branch}} 106 return; // expected-warning{{Potential leak}} 107 // expected-note@-1{{Object leaked}} 108 arr1->release(); 109 } 110 111 void check_dynamic_cast_null_check() { 112 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); // expected-note{{Call to function 'generateObject' returns an OSObject}} 113 // expected-warning@-1{{Potential leak of an object}} 114 // expected-note@-2{{Object leaked}} 115 if (!arr) 116 return; 117 arr->release(); 118 } 119 120 void use_after_release() { 121 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}} 122 arr->release(); // expected-note{{Object released}} 123 arr->getCount(); // expected-warning{{Reference-counted object is used after it is released}} 124 // expected-note@-1{{Reference-counted object is used after it is released}} 125 } 126 127 void potential_leak() { 128 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}} 129 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}} 130 arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}} 131 arr->getCount(); 132 } // expected-warning{{Potential leak of an object stored into 'arr'}} 133 // 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}} 134 135 void proper_cleanup() { 136 OSArray *arr = OSArray::withCapacity(10); // +1 137 arr->retain(); // +2 138 arr->release(); // +1 139 arr->getCount(); 140 arr->release(); // 0 141 } 142 143 struct ArrayOwner { 144 OSArray *arr; 145 146 OSArray *getArray() { 147 return arr; 148 } 149 150 OSArray *createArray() { 151 return OSArray::withCapacity(10); 152 } 153 154 OSArray *createArraySourceUnknown(); 155 156 OSArray *getArraySourceUnknown(); 157 }; 158 159 unsigned int no_warning_on_getter(ArrayOwner *owner) { 160 OSArray *arr = owner->getArray(); 161 return arr->getCount(); 162 } 163 164 unsigned int warn_on_overrelease(ArrayOwner *owner) { 165 OSArray *arr = owner->getArray(); // expected-note{{function call returns an OSObject of type struct OSArray * with a +0 retain count}} 166 arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} 167 // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} 168 return arr->getCount(); 169 } 170 171 unsigned int nowarn_on_release_of_created(ArrayOwner *owner) { 172 OSArray *arr = owner->createArray(); 173 unsigned int out = arr->getCount(); 174 arr->release(); 175 return out; 176 } 177 178 unsigned int nowarn_on_release_of_created_source_unknown(ArrayOwner *owner) { 179 OSArray *arr = owner->createArraySourceUnknown(); 180 unsigned int out = arr->getCount(); 181 arr->release(); 182 return out; 183 } 184 185 unsigned int no_warn_ok_release(ArrayOwner *owner) { 186 OSArray *arr = owner->getArray(); // +0 187 arr->retain(); // +1 188 arr->release(); // +0 189 return arr->getCount(); // no-warning 190 } 191 192 unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) { 193 OSArray *arr = owner->getArraySourceUnknown(); // expected-note{{function call returns an OSObject of type struct OSArray * with a +0 retain count}} 194 arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} 195 // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}} 196 return arr->getCount(); 197 } 198 199 unsigned int ok_release_with_unknown_source(ArrayOwner *owner) { 200 OSArray *arr = owner->getArraySourceUnknown(); // +0 201 arr->retain(); // +1 202 arr->release(); // +0 203 return arr->getCount(); 204 } 205