blob: 398857f45456b805af73fda8f8ff76c27aaa0017 [file] [log] [blame]
George Karpenkov57ef3a02018-10-31 17:38:12 +00001// RUN: %clang_analyze_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-output=text -verify %s
George Karpenkovab0011e2018-08-23 00:26:59 +00002
George Karpenkov41dc8de2018-10-11 22:59:16 +00003struct OSMetaClass;
4
George Karpenkovb43772d2018-11-30 02:18:50 +00005#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))
George Karpenkov081c4772018-10-23 23:11:50 +00008
George Karpenkov41dc8de2018-10-11 22:59:16 +00009#define OSTypeID(type) (type::metaClass)
10
11#define OSDynamicCast(type, inst) \
12 ((type *) OSMetaClassBase::safeMetaCast((inst), OSTypeID(type)))
13
George Karpenkovbe3f4bd2018-11-30 20:43:42 +000014using size_t = decltype(sizeof(int));
15
George Karpenkovab0011e2018-08-23 00:26:59 +000016struct OSObject {
17 virtual void retain();
George Karpenkov48de5822018-10-23 23:11:30 +000018 virtual void release() {};
George Karpenkovbe3f4bd2018-11-30 20:43:42 +000019 virtual void free();
George Karpenkovab0011e2018-08-23 00:26:59 +000020 virtual ~OSObject(){}
George Karpenkov41dc8de2018-10-11 22:59:16 +000021
George Karpenkov3c2ed8f2018-10-25 23:38:07 +000022 unsigned int foo() { return 42; }
23
George Karpenkova717bc72018-12-05 18:34:54 +000024 virtual OS_RETURNS_NOT_RETAINED OSObject *identity();
25
George Karpenkov41dc8de2018-10-11 22:59:16 +000026 static OSObject *generateObject(int);
27
George Karpenkov3bdbeb12018-11-30 02:18:10 +000028 static OSObject *getObject();
29 static OSObject *GetObject();
30
George Karpenkovbe3f4bd2018-11-30 20:43:42 +000031 static void * operator new(size_t size);
32
George Karpenkov41dc8de2018-10-11 22:59:16 +000033 static const OSMetaClass * const metaClass;
George Karpenkovab0011e2018-08-23 00:26:59 +000034};
35
George Karpenkov83fb5362018-10-31 17:38:46 +000036struct OSIterator : public OSObject {
George Karpenkova1c3bb82018-11-30 02:17:31 +000037
38 static const OSMetaClass * const metaClass;
George Karpenkov83fb5362018-10-31 17:38:46 +000039};
40
George Karpenkovab0011e2018-08-23 00:26:59 +000041struct OSArray : public OSObject {
42 unsigned int getCount();
43
George Karpenkova717bc72018-12-05 18:34:54 +000044 OSIterator * getIterator();
45
46 OSObject *identity() override;
47
48 virtual void consumeReference(OS_CONSUME OSArray *other);
49
George Karpenkov62db8862018-11-30 02:18:23 +000050 static OSArray *generateArrayHasCode() {
51 return new OSArray;
52 }
53
George Karpenkovab0011e2018-08-23 00:26:59 +000054 static OSArray *withCapacity(unsigned int capacity);
George Karpenkov081c4772018-10-23 23:11:50 +000055 static void consumeArray(OS_CONSUME OSArray * array);
56
57 static OSArray* consumeArrayHasCode(OS_CONSUME OSArray * array) {
58 return nullptr;
59 }
60
61 static OS_RETURNS_NOT_RETAINED OSArray *MaskedGetter();
62 static OS_RETURNS_RETAINED OSArray *getOoopsActuallyCreate();
63
George Karpenkov41dc8de2018-10-11 22:59:16 +000064 static const OSMetaClass * const metaClass;
George Karpenkovab0011e2018-08-23 00:26:59 +000065};
66
George Karpenkova717bc72018-12-05 18:34:54 +000067struct MyArray : public OSArray {
68 void consumeReference(OSArray *other) override;
69
70 OSObject *identity() override;
71};
72
George Karpenkov081c4772018-10-23 23:11:50 +000073struct OtherStruct {
74 static void doNothingToArray(OSArray *array);
George Karpenkov3cfa04e2018-10-25 23:38:41 +000075 OtherStruct(OSArray *arr);
George Karpenkov081c4772018-10-23 23:11:50 +000076};
77
George Karpenkov41dc8de2018-10-11 22:59:16 +000078struct OSMetaClassBase {
79 static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta);
80};
81
George Karpenkova717bc72018-12-05 18:34:54 +000082void check_param_attribute_propagation(MyArray *parent) {
83 OSArray *arr = new OSArray;
84 parent->consumeReference(arr);
85}
86
87unsigned int check_attribute_propagation(OSArray *arr) {
88 OSObject *other = arr->identity();
89 OSArray *casted = OSDynamicCast(OSArray, other);
90 if (casted)
91 return casted->getCount();
92 return 0;
93}
94
95unsigned int check_attribute_indirect_propagation(MyArray *arr) {
96 OSObject *other = arr->identity();
97 OSArray *casted = OSDynamicCast(OSArray, other);
98 if (casted)
99 return casted->getCount();
100 return 0;
101}
102
George Karpenkovbe3f4bd2018-11-30 20:43:42 +0000103void check_free_no_error() {
104 OSArray *arr = OSArray::withCapacity(10);
105 arr->retain();
106 arr->retain();
107 arr->retain();
108 arr->free();
109}
110
111void check_free_use_after_free() {
112 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
113 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
114 arr->free(); // expected-note{{Object released}}
115 arr->retain(); // expected-warning{{Reference-counted object is used after it is released}}
116 // expected-note@-1{{Reference-counted object is used after it is released}}
117}
118
119unsigned int check_leak_explicit_new() {
120 OSArray *arr = new OSArray; // expected-note{{Operator new returns an OSObject of type OSArray with a +1 retain count}}
121 return arr->getCount(); // expected-note{{Object leaked: allocated object of type OSArray is not referenced later in this execution path and has a retain count of +1}}
122 // expected-warning@-1{{Potential leak of an object of type OSArray}}
123}
124
125unsigned int check_leak_factory() {
126 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
127 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}}
128 // expected-warning@-1{{Potential leak of an object stored into 'arr'}}
129}
130
George Karpenkov3bdbeb12018-11-30 02:18:10 +0000131void check_get_object() {
132 OSObject::getObject();
133}
134
135void check_Get_object() {
136 OSObject::GetObject();
137}
138
George Karpenkov83fb5362018-10-31 17:38:46 +0000139void check_custom_iterator_rule(OSArray *arr) {
140 OSIterator *it = arr->getIterator();
141 it->release();
142}
143
George Karpenkove2f09542018-11-30 02:17:57 +0000144void check_iterator_leak(OSArray *arr) {
George Karpenkov62db8862018-11-30 02:18:23 +0000145 arr->getIterator(); // expected-note{{Call to method 'OSArray::getIterator' returns an OSObject of type OSIterator with a +1 retain count}}
146} // expected-note{{Object leaked: allocated object of type OSIterator is not referenced later}}
147 // expected-warning@-1{{Potential leak of an object of type OSIterator}}
George Karpenkove2f09542018-11-30 02:17:57 +0000148
George Karpenkov081c4772018-10-23 23:11:50 +0000149void check_no_invalidation() {
George Karpenkove2f09542018-11-30 02:17:57 +0000150 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
George Karpenkov081c4772018-10-23 23:11:50 +0000151 OtherStruct::doNothingToArray(arr);
152} // expected-warning{{Potential leak of an object stored into 'arr'}}
153 // expected-note@-1{{Object leaked}}
154
George Karpenkov3cfa04e2018-10-25 23:38:41 +0000155void check_no_invalidation_other_struct() {
George Karpenkove2f09542018-11-30 02:17:57 +0000156 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
George Karpenkov3cfa04e2018-10-25 23:38:41 +0000157 OtherStruct other(arr); // expected-warning{{Potential leak}}
158 // expected-note@-1{{Object leaked}}
159}
160
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000161struct ArrayOwner : public OSObject {
162 OSArray *arr;
163 ArrayOwner(OSArray *arr) : arr(arr) {}
164
165 static ArrayOwner* create(OSArray *arr) {
166 return new ArrayOwner(arr);
167 }
168
169 OSArray *getArray() {
170 return arr;
171 }
172
173 OSArray *createArray() {
174 return OSArray::withCapacity(10);
175 }
176
177 OSArray *createArraySourceUnknown();
178
179 OSArray *getArraySourceUnknown();
180};
181
George Karpenkova1c3bb82018-11-30 02:17:31 +0000182OSArray *generateArray() {
George Karpenkov62db8862018-11-30 02:18:23 +0000183 return OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
184 // expected-note@-1{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
George Karpenkova1c3bb82018-11-30 02:17:31 +0000185}
186
187unsigned int check_leak_good_error_message() {
188 unsigned int out;
189 {
190 OSArray *leaked = generateArray(); // expected-note{{Calling 'generateArray'}}
191 // expected-note@-1{{Returning from 'generateArray'}}
192 out = leaked->getCount(); // expected-warning{{Potential leak of an object stored into 'leaked'}}
193 // 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}}
194 }
195 return out;
196}
197
198unsigned int check_leak_msg_temporary() {
George Karpenkovf893ea12018-11-30 02:17:44 +0000199 return generateArray()->getCount(); // expected-warning{{Potential leak of an object}}
200 // expected-note@-1{{Calling 'generateArray'}}
201 // expected-note@-2{{Returning from 'generateArray'}}
202 // 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}}
George Karpenkova1c3bb82018-11-30 02:17:31 +0000203}
204
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000205void check_confusing_getters() {
206 OSArray *arr = OSArray::withCapacity(10);
207
208 ArrayOwner *AO = ArrayOwner::create(arr);
209 AO->getArray();
210
211 AO->release();
212 arr->release();
213}
214
George Karpenkov081c4772018-10-23 23:11:50 +0000215void check_rc_consumed() {
216 OSArray *arr = OSArray::withCapacity(10);
217 OSArray::consumeArray(arr);
218}
219
220void check_rc_consume_temporary() {
221 OSArray::consumeArray(OSArray::withCapacity(10));
222}
223
224void check_rc_getter() {
225 OSArray *arr = OSArray::MaskedGetter();
226 (void)arr;
227}
228
229void check_rc_create() {
230 OSArray *arr = OSArray::getOoopsActuallyCreate();
231 arr->release();
232}
233
234
George Karpenkov41dc8de2018-10-11 22:59:16 +0000235void check_dynamic_cast() {
236 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1));
237 arr->release();
238}
239
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000240unsigned int check_dynamic_cast_no_null_on_orig(OSObject *obj) {
241 OSArray *arr = OSDynamicCast(OSArray, obj);
242 if (arr) {
243 return arr->getCount();
244 } else {
245
246 // The fact that dynamic cast has failed should not imply that
247 // the input object was null.
248 return obj->foo(); // no-warning
249 }
250}
251
252void check_dynamic_cast_null_branch(OSObject *obj) {
George Karpenkove2f09542018-11-30 02:17:57 +0000253 OSArray *arr1 = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000254 OSArray *arr = OSDynamicCast(OSArray, obj);
255 if (!arr) // expected-note{{Taking true branch}}
George Karpenkova1c3bb82018-11-30 02:17:31 +0000256 return; // expected-warning{{Potential leak of an object stored into 'arr1'}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000257 // expected-note@-1{{Object leaked}}
258 arr1->release();
259}
260
George Karpenkov41dc8de2018-10-11 22:59:16 +0000261void check_dynamic_cast_null_check() {
George Karpenkove2f09542018-11-30 02:17:57 +0000262 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); // expected-note{{Call to method 'OSObject::generateObject' returns an OSObject}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000263 // expected-warning@-1{{Potential leak of an object}}
264 // expected-note@-2{{Object leaked}}
George Karpenkov41dc8de2018-10-11 22:59:16 +0000265 if (!arr)
266 return;
267 arr->release();
268}
269
George Karpenkovab0011e2018-08-23 00:26:59 +0000270void use_after_release() {
George Karpenkov62db8862018-11-30 02:18:23 +0000271 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
George Karpenkovab0011e2018-08-23 00:26:59 +0000272 arr->release(); // expected-note{{Object released}}
273 arr->getCount(); // expected-warning{{Reference-counted object is used after it is released}}
274 // expected-note@-1{{Reference-counted object is used after it is released}}
275}
276
277void potential_leak() {
George Karpenkov62db8862018-11-30 02:18:23 +0000278 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
George Karpenkovab0011e2018-08-23 00:26:59 +0000279 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
280 arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}}
281 arr->getCount();
282} // expected-warning{{Potential leak of an object stored into 'arr'}}
283 // 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}}
284
285void proper_cleanup() {
286 OSArray *arr = OSArray::withCapacity(10); // +1
287 arr->retain(); // +2
288 arr->release(); // +1
289 arr->getCount();
290 arr->release(); // 0
291}
292
George Karpenkovab0011e2018-08-23 00:26:59 +0000293unsigned int no_warning_on_getter(ArrayOwner *owner) {
294 OSArray *arr = owner->getArray();
295 return arr->getCount();
296}
297
298unsigned int warn_on_overrelease(ArrayOwner *owner) {
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000299 // FIXME: summaries are not applied in case the source of the getter/setter
300 // is known.
301 // rdar://45681203
302 OSArray *arr = owner->getArray();
303 arr->release();
George Karpenkovab0011e2018-08-23 00:26:59 +0000304 return arr->getCount();
305}
306
307unsigned int nowarn_on_release_of_created(ArrayOwner *owner) {
308 OSArray *arr = owner->createArray();
309 unsigned int out = arr->getCount();
310 arr->release();
311 return out;
312}
313
314unsigned int nowarn_on_release_of_created_source_unknown(ArrayOwner *owner) {
315 OSArray *arr = owner->createArraySourceUnknown();
316 unsigned int out = arr->getCount();
317 arr->release();
318 return out;
319}
320
321unsigned int no_warn_ok_release(ArrayOwner *owner) {
322 OSArray *arr = owner->getArray(); // +0
323 arr->retain(); // +1
324 arr->release(); // +0
325 return arr->getCount(); // no-warning
326}
327
328unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) {
George Karpenkove2f09542018-11-30 02:17:57 +0000329 OSArray *arr = owner->getArraySourceUnknown(); // expected-note{{Call to method 'ArrayOwner::getArraySourceUnknown' returns an OSObject of type OSArray with a +0 retain count}}
George Karpenkovab0011e2018-08-23 00:26:59 +0000330 arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
331 // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
332 return arr->getCount();
333}
334
335unsigned int ok_release_with_unknown_source(ArrayOwner *owner) {
336 OSArray *arr = owner->getArraySourceUnknown(); // +0
337 arr->retain(); // +1
338 arr->release(); // +0
339 return arr->getCount();
340}