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