blob: ca8a45c37f39c647b805e2c212bae0236fc147a2 [file] [log] [blame]
Artem Dergachev46f34622018-12-15 02:13:26 +00001// RUN: %clang_analyze_cc1 -fblocks -analyze -analyzer-output=text\
2// RUN: -analyzer-checker=core,osx -verify %s
George Karpenkovab0011e2018-08-23 00:26:59 +00003
George Karpenkov41dc8de2018-10-11 22:59:16 +00004struct OSMetaClass;
5
George Karpenkovb43772d2018-11-30 02:18:50 +00006#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))
George Karpenkovb0b61952018-12-06 22:07:12 +00009#define OS_CONSUMES_THIS __attribute__((os_consumes_this))
George Karpenkov081c4772018-10-23 23:11:50 +000010
George Karpenkov41dc8de2018-10-11 22:59:16 +000011#define OSTypeID(type) (type::metaClass)
12
13#define OSDynamicCast(type, inst) \
14 ((type *) OSMetaClassBase::safeMetaCast((inst), OSTypeID(type)))
15
George Karpenkovbe3f4bd2018-11-30 20:43:42 +000016using size_t = decltype(sizeof(int));
17
George Karpenkovab0011e2018-08-23 00:26:59 +000018struct OSObject {
19 virtual void retain();
George Karpenkov48de5822018-10-23 23:11:30 +000020 virtual void release() {};
George Karpenkovbe3f4bd2018-11-30 20:43:42 +000021 virtual void free();
George Karpenkovab0011e2018-08-23 00:26:59 +000022 virtual ~OSObject(){}
George Karpenkov41dc8de2018-10-11 22:59:16 +000023
George Karpenkov3c2ed8f2018-10-25 23:38:07 +000024 unsigned int foo() { return 42; }
25
George Karpenkova717bc72018-12-05 18:34:54 +000026 virtual OS_RETURNS_NOT_RETAINED OSObject *identity();
27
George Karpenkov41dc8de2018-10-11 22:59:16 +000028 static OSObject *generateObject(int);
29
George Karpenkov3bdbeb12018-11-30 02:18:10 +000030 static OSObject *getObject();
31 static OSObject *GetObject();
32
George Karpenkovbe3f4bd2018-11-30 20:43:42 +000033 static void * operator new(size_t size);
34
George Karpenkov41dc8de2018-10-11 22:59:16 +000035 static const OSMetaClass * const metaClass;
George Karpenkovab0011e2018-08-23 00:26:59 +000036};
37
George Karpenkov83fb5362018-10-31 17:38:46 +000038struct OSIterator : public OSObject {
George Karpenkova1c3bb82018-11-30 02:17:31 +000039
40 static const OSMetaClass * const metaClass;
George Karpenkov83fb5362018-10-31 17:38:46 +000041};
42
George Karpenkovab0011e2018-08-23 00:26:59 +000043struct OSArray : public OSObject {
44 unsigned int getCount();
45
George Karpenkova717bc72018-12-05 18:34:54 +000046 OSIterator * getIterator();
47
48 OSObject *identity() override;
49
George Karpenkova71ec6c2018-12-06 22:06:44 +000050 virtual OSObject *generateObject(OSObject *input);
51
George Karpenkova717bc72018-12-05 18:34:54 +000052 virtual void consumeReference(OS_CONSUME OSArray *other);
53
George Karpenkovb0b61952018-12-06 22:07:12 +000054 void putIntoArray(OSArray *array) OS_CONSUMES_THIS;
55
56 template <typename T>
57 void putIntoT(T *owner) OS_CONSUMES_THIS;
58
George Karpenkov62db8862018-11-30 02:18:23 +000059 static OSArray *generateArrayHasCode() {
60 return new OSArray;
61 }
62
George Karpenkovab0011e2018-08-23 00:26:59 +000063 static OSArray *withCapacity(unsigned int capacity);
George Karpenkov081c4772018-10-23 23:11:50 +000064 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
George Karpenkov41dc8de2018-10-11 22:59:16 +000073 static const OSMetaClass * const metaClass;
George Karpenkovab0011e2018-08-23 00:26:59 +000074};
75
George Karpenkova717bc72018-12-05 18:34:54 +000076struct MyArray : public OSArray {
77 void consumeReference(OSArray *other) override;
78
79 OSObject *identity() override;
George Karpenkova71ec6c2018-12-06 22:06:44 +000080
81 OSObject *generateObject(OSObject *input) override;
George Karpenkova717bc72018-12-05 18:34:54 +000082};
83
George Karpenkov081c4772018-10-23 23:11:50 +000084struct OtherStruct {
85 static void doNothingToArray(OSArray *array);
George Karpenkov3cfa04e2018-10-25 23:38:41 +000086 OtherStruct(OSArray *arr);
George Karpenkov081c4772018-10-23 23:11:50 +000087};
88
George Karpenkov41dc8de2018-10-11 22:59:16 +000089struct OSMetaClassBase {
90 static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta);
91};
92
George Karpenkov041c9fa2018-12-08 01:18:40 +000093void escape(void *);
George Karpenkov255b0582018-12-21 19:13:40 +000094void escape_with_source(void *p) {}
George Karpenkovff014862018-12-11 01:13:40 +000095bool coin();
96
George Karpenkovf5085322018-12-21 02:16:23 +000097bool 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 }
George Karpenkov79f03402018-12-21 19:13:28 +0000103 return false; // expected-note{{Parameter 'obj' is marked as consuming, but the function did not consume the reference}}
George Karpenkovf5085322018-12-21 02:16:23 +0000104}
105
George Karpenkovff014862018-12-11 01:13:40 +0000106bool 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 }
George Karpenkov79f03402018-12-21 19:13:28 +0000112 return false; // expected-note{{Parameter 'obj' is marked as consuming, but the function did not consume the reference}}
George Karpenkovff014862018-12-11 01:13:40 +0000113}
114
115void os_consume_ok(OS_CONSUME OSObject *obj) {
116 escape(obj);
117}
118
119void use_os_consume_violation() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000120 OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
George Karpenkovff014862018-12-11 01:13:40 +0000121 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
George Karpenkovf5085322018-12-21 02:16:23 +0000126void use_os_consume_violation_two_args() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000127 OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
George Karpenkovf5085322018-12-21 02:16:23 +0000128 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
George Karpenkovff014862018-12-11 01:13:40 +0000133void use_os_consume_ok() {
134 OSObject *obj = new OSObject;
135 os_consume_ok(obj);
136}
George Karpenkov041c9fa2018-12-08 01:18:40 +0000137
138void test_escaping_into_voidstar() {
139 OSObject *obj = new OSObject;
140 escape(obj);
141}
142
George Karpenkov255b0582018-12-21 19:13:40 +0000143void test_escape_has_source() {
144 OSObject *obj = new OSObject;
145 if (obj)
George Karpenkovd76cc592018-12-21 19:40:44 +0000146 escape_with_source(obj);
George Karpenkov255b0582018-12-21 19:13:40 +0000147 return;
148}
149
George Karpenkova71ec6c2018-12-06 22:06:44 +0000150void 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
George Karpenkova717bc72018-12-05 18:34:54 +0000158void check_param_attribute_propagation(MyArray *parent) {
159 OSArray *arr = new OSArray;
160 parent->consumeReference(arr);
161}
162
163unsigned 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
171unsigned 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
George Karpenkovb0b61952018-12-06 22:07:12 +0000179void check_consumes_this(OSArray *owner) {
180 OSArray *arr = new OSArray;
181 arr->putIntoArray(owner);
182}
183
184void check_consumes_this_with_template(OSArray *owner) {
185 OSArray *arr = new OSArray;
186 arr->putIntoT(owner);
187}
188
George Karpenkovbe3f4bd2018-11-30 20:43:42 +0000189void check_free_no_error() {
190 OSArray *arr = OSArray::withCapacity(10);
191 arr->retain();
192 arr->retain();
193 arr->retain();
194 arr->free();
195}
196
197void check_free_use_after_free() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000198 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}
George Karpenkovbe3f4bd2018-11-30 20:43:42 +0000199 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
205unsigned int check_leak_explicit_new() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000206 OSArray *arr = new OSArray; // expected-note{{Operator 'new' returns an OSObject of type 'OSArray' with a +1 retain count}}
George Karpenkov79ed11c2018-12-11 01:13:20 +0000207 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'}}
George Karpenkovbe3f4bd2018-11-30 20:43:42 +0000209}
210
211unsigned int check_leak_factory() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000212 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}
George Karpenkovbe3f4bd2018-11-30 20:43:42 +0000213 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
George Karpenkov3bdbeb12018-11-30 02:18:10 +0000217void check_get_object() {
218 OSObject::getObject();
219}
220
221void check_Get_object() {
222 OSObject::GetObject();
223}
224
George Karpenkov83fb5362018-10-31 17:38:46 +0000225void check_custom_iterator_rule(OSArray *arr) {
226 OSIterator *it = arr->getIterator();
227 it->release();
228}
229
George Karpenkove2f09542018-11-30 02:17:57 +0000230void check_iterator_leak(OSArray *arr) {
George Karpenkov4f64b382019-01-10 18:15:57 +0000231 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}}'
George Karpenkove2f09542018-11-30 02:17:57 +0000234
George Karpenkov081c4772018-10-23 23:11:50 +0000235void check_no_invalidation() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000236 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 +0000237 OtherStruct::doNothingToArray(arr);
238} // expected-warning{{Potential leak of an object stored into 'arr'}}
239 // expected-note@-1{{Object leaked}}
240
George Karpenkov3cfa04e2018-10-25 23:38:41 +0000241void check_no_invalidation_other_struct() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000242 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 +0000243 OtherStruct other(arr); // expected-warning{{Potential leak}}
244 // expected-note@-1{{Object leaked}}
245}
246
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000247struct 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
George Karpenkova1c3bb82018-11-30 02:17:31 +0000268OSArray *generateArray() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000269 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}}
George Karpenkova1c3bb82018-11-30 02:17:31 +0000271}
272
273unsigned 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
284unsigned int check_leak_msg_temporary() {
George Karpenkovf893ea12018-11-30 02:17:44 +0000285 return generateArray()->getCount(); // expected-warning{{Potential leak of an object}}
286 // expected-note@-1{{Calling 'generateArray'}}
287 // expected-note@-2{{Returning from 'generateArray'}}
George Karpenkov4f64b382019-01-10 18:15:57 +0000288 // 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 +0000289}
290
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000291void 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
George Karpenkov081c4772018-10-23 23:11:50 +0000301void check_rc_consumed() {
302 OSArray *arr = OSArray::withCapacity(10);
303 OSArray::consumeArray(arr);
304}
305
306void check_rc_consume_temporary() {
307 OSArray::consumeArray(OSArray::withCapacity(10));
308}
309
310void check_rc_getter() {
311 OSArray *arr = OSArray::MaskedGetter();
312 (void)arr;
313}
314
315void check_rc_create() {
316 OSArray *arr = OSArray::getOoopsActuallyCreate();
317 arr->release();
318}
319
320
George Karpenkov41dc8de2018-10-11 22:59:16 +0000321void check_dynamic_cast() {
322 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1));
323 arr->release();
324}
325
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000326unsigned 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
338void check_dynamic_cast_null_branch(OSObject *obj) {
George Karpenkove2f09542018-11-30 02:17:57 +0000339 OSArray *arr1 = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000340 OSArray *arr = OSDynamicCast(OSArray, obj);
341 if (!arr) // expected-note{{Taking true branch}}
George Karpenkova1c3bb82018-11-30 02:17:31 +0000342 return; // expected-warning{{Potential leak of an object stored into 'arr1'}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000343 // expected-note@-1{{Object leaked}}
344 arr1->release();
345}
346
George Karpenkov41dc8de2018-10-11 22:59:16 +0000347void check_dynamic_cast_null_check() {
George Karpenkove2f09542018-11-30 02:17:57 +0000348 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); // expected-note{{Call to method 'OSObject::generateObject' returns an OSObject}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000349 // expected-warning@-1{{Potential leak of an object}}
350 // expected-note@-2{{Object leaked}}
George Karpenkov41dc8de2018-10-11 22:59:16 +0000351 if (!arr)
352 return;
353 arr->release();
354}
355
George Karpenkovab0011e2018-08-23 00:26:59 +0000356void use_after_release() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000357 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 +0000358 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
363void potential_leak() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000364 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 +0000365 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
371void 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
George Karpenkovab0011e2018-08-23 00:26:59 +0000379unsigned int no_warning_on_getter(ArrayOwner *owner) {
380 OSArray *arr = owner->getArray();
381 return arr->getCount();
382}
383
384unsigned int warn_on_overrelease(ArrayOwner *owner) {
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000385 // 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();
George Karpenkovab0011e2018-08-23 00:26:59 +0000390 return arr->getCount();
391}
392
393unsigned 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
400unsigned 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
407unsigned 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
414unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) {
George Karpenkov4f64b382019-01-10 18:15:57 +0000415 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 +0000416 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
421unsigned 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}
Artem Dergachev46f34622018-12-15 02:13:26 +0000427
428OSObject *getObject();
429typedef bool (^Blk)(OSObject *);
430
431void test_escape_to_unknown_block(Blk blk) {
432 blk(getObject()); // no-crash
433}
434