blob: 9d11a0623167c4bb8c75fc110f772f5f3043542b [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))
George Karpenkov5be959c2019-01-11 23:35:17 +00008#define OS_RETURNS_RETAINED_ON_ZERO __attribute__((os_returns_retained_on_zero))
9#define OS_RETURNS_RETAINED_ON_NONZERO __attribute__((os_returns_retained_on_non_zero))
George Karpenkovb43772d2018-11-30 02:18:50 +000010#define OS_RETURNS_NOT_RETAINED __attribute__((os_returns_not_retained))
George Karpenkovb0b61952018-12-06 22:07:12 +000011#define OS_CONSUMES_THIS __attribute__((os_consumes_this))
George Karpenkov081c4772018-10-23 23:11:50 +000012
George Karpenkov41dc8de2018-10-11 22:59:16 +000013#define OSTypeID(type) (type::metaClass)
14
15#define OSDynamicCast(type, inst) \
16 ((type *) OSMetaClassBase::safeMetaCast((inst), OSTypeID(type)))
17
George Karpenkovbe3f4bd2018-11-30 20:43:42 +000018using size_t = decltype(sizeof(int));
19
George Karpenkovab0011e2018-08-23 00:26:59 +000020struct OSObject {
21 virtual void retain();
George Karpenkov48de5822018-10-23 23:11:30 +000022 virtual void release() {};
George Karpenkovbe3f4bd2018-11-30 20:43:42 +000023 virtual void free();
George Karpenkovab0011e2018-08-23 00:26:59 +000024 virtual ~OSObject(){}
George Karpenkov41dc8de2018-10-11 22:59:16 +000025
George Karpenkov3c2ed8f2018-10-25 23:38:07 +000026 unsigned int foo() { return 42; }
27
George Karpenkova717bc72018-12-05 18:34:54 +000028 virtual OS_RETURNS_NOT_RETAINED OSObject *identity();
29
George Karpenkov41dc8de2018-10-11 22:59:16 +000030 static OSObject *generateObject(int);
31
George Karpenkov3bdbeb12018-11-30 02:18:10 +000032 static OSObject *getObject();
33 static OSObject *GetObject();
34
George Karpenkovbe3f4bd2018-11-30 20:43:42 +000035 static void * operator new(size_t size);
36
George Karpenkov41dc8de2018-10-11 22:59:16 +000037 static const OSMetaClass * const metaClass;
George Karpenkovab0011e2018-08-23 00:26:59 +000038};
39
George Karpenkov83fb5362018-10-31 17:38:46 +000040struct OSIterator : public OSObject {
George Karpenkova1c3bb82018-11-30 02:17:31 +000041
42 static const OSMetaClass * const metaClass;
George Karpenkov83fb5362018-10-31 17:38:46 +000043};
44
George Karpenkovab0011e2018-08-23 00:26:59 +000045struct OSArray : public OSObject {
46 unsigned int getCount();
47
George Karpenkova717bc72018-12-05 18:34:54 +000048 OSIterator * getIterator();
49
50 OSObject *identity() override;
51
George Karpenkova71ec6c2018-12-06 22:06:44 +000052 virtual OSObject *generateObject(OSObject *input);
53
George Karpenkova717bc72018-12-05 18:34:54 +000054 virtual void consumeReference(OS_CONSUME OSArray *other);
55
George Karpenkovb0b61952018-12-06 22:07:12 +000056 void putIntoArray(OSArray *array) OS_CONSUMES_THIS;
57
58 template <typename T>
59 void putIntoT(T *owner) OS_CONSUMES_THIS;
60
George Karpenkov62db8862018-11-30 02:18:23 +000061 static OSArray *generateArrayHasCode() {
62 return new OSArray;
63 }
64
George Karpenkovab0011e2018-08-23 00:26:59 +000065 static OSArray *withCapacity(unsigned int capacity);
George Karpenkov081c4772018-10-23 23:11:50 +000066 static void consumeArray(OS_CONSUME OSArray * array);
67
68 static OSArray* consumeArrayHasCode(OS_CONSUME OSArray * array) {
69 return nullptr;
70 }
71
72 static OS_RETURNS_NOT_RETAINED OSArray *MaskedGetter();
73 static OS_RETURNS_RETAINED OSArray *getOoopsActuallyCreate();
74
George Karpenkov41dc8de2018-10-11 22:59:16 +000075 static const OSMetaClass * const metaClass;
George Karpenkovab0011e2018-08-23 00:26:59 +000076};
77
George Karpenkova717bc72018-12-05 18:34:54 +000078struct MyArray : public OSArray {
79 void consumeReference(OSArray *other) override;
80
81 OSObject *identity() override;
George Karpenkova71ec6c2018-12-06 22:06:44 +000082
83 OSObject *generateObject(OSObject *input) override;
George Karpenkova717bc72018-12-05 18:34:54 +000084};
85
George Karpenkov081c4772018-10-23 23:11:50 +000086struct OtherStruct {
87 static void doNothingToArray(OSArray *array);
George Karpenkov3cfa04e2018-10-25 23:38:41 +000088 OtherStruct(OSArray *arr);
George Karpenkov081c4772018-10-23 23:11:50 +000089};
90
George Karpenkov41dc8de2018-10-11 22:59:16 +000091struct OSMetaClassBase {
92 static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta);
93};
94
George Karpenkov041c9fa2018-12-08 01:18:40 +000095void escape(void *);
George Karpenkov255b0582018-12-21 19:13:40 +000096void escape_with_source(void *p) {}
George Karpenkovff014862018-12-11 01:13:40 +000097bool coin();
98
George Karpenkov5be959c2019-01-11 23:35:17 +000099typedef int kern_return_t;
100typedef kern_return_t IOReturn;
101typedef kern_return_t OSReturn;
102#define kOSReturnSuccess 0
103#define kIOReturnSuccess 0
104
105bool write_into_out_param_on_success(OS_RETURNS_RETAINED OSObject **obj);
106
107void use_out_param() {
108 OSObject *obj;
109 if (write_into_out_param_on_success(&obj)) {
110 obj->release();
111 }
112}
113
114void use_out_param_leak() {
115 OSObject *obj;
116 write_into_out_param_on_success(&obj); // expected-note-re{{Call to function 'write_into_out_param_on_success' writes an OSObject of type 'OSObject' with a +1 retain count into an out parameter 'obj' (assuming the call returns non-zero){{$}}}}
117} // expected-warning{{Potential leak of an object stored into 'obj'}}
118 // expected-note@-1{{Object leaked: object allocated and stored into 'obj' is not referenced later in this execution path and has a retain count of +1}}
119
120bool write_into_out_param_on_failure(OS_RETURNS_RETAINED_ON_ZERO OSObject **obj);
121
122void use_out_param_leak2() {
123 OSObject *obj;
124 write_into_out_param_on_failure(&obj); // expected-note-re{{Call to function 'write_into_out_param_on_failure' writes an OSObject of type 'OSObject' with a +1 retain count into an out parameter 'obj' (assuming the call returns zero){{$}}}}
125} // expected-warning{{Potential leak of an object stored into 'obj'}}
126 // expected-note@-1{{Object leaked: object allocated and stored into 'obj' is not referenced later in this execution path and has a retain count of +1}}
127
128void use_out_param_on_failure() {
129 OSObject *obj;
130 if (!write_into_out_param_on_failure(&obj)) {
131 obj->release();
132 }
133}
134
135IOReturn write_into_out_param_on_nonzero(OS_RETURNS_RETAINED_ON_NONZERO OSObject **obj);
136
137void use_out_param_on_nonzero() {
138 OSObject *obj;
139 if (write_into_out_param_on_nonzero(&obj) != kIOReturnSuccess) {
140 obj->release();
141 }
142}
143
144bool write_into_two_out_params(OS_RETURNS_RETAINED OSObject **a,
145 OS_RETURNS_RETAINED OSObject **b);
146
147void use_write_into_two_out_params() {
148 OSObject *obj1;
149 OSObject *obj2;
150 if (write_into_two_out_params(&obj1, &obj2)) {
151 obj1->release();
152 obj2->release();
153 }
154}
155
156void use_write_two_out_params_leak() {
157 OSObject *obj1;
158 OSObject *obj2;
159 write_into_two_out_params(&obj1, &obj2); // expected-note-re{{Call to function 'write_into_two_out_params' writes an OSObject of type 'OSObject' with a +1 retain count into an out parameter 'a' (assuming the call returns non-zero){{$}}}}
160 // expected-note-re@-1{{Call to function 'write_into_two_out_params' writes an OSObject of type 'OSObject' with a +1 retain count into an out parameter 'b' (assuming the call returns non-zero){{$}}}}
161} // expected-warning{{Potential leak of an object stored into 'obj1'}}
162 // expected-warning@-1{{Potential leak of an object stored into 'obj2'}}
163 // expected-note@-2{{Object leaked: object allocated and stored into 'obj1' is not referenced later in this execution path and has a retain count of +1}}
164 // expected-note@-3{{Object leaked: object allocated and stored into 'obj2' is not referenced later in this execution path and has a retain count of +1}}
165
166void always_write_into_two_out_params(OS_RETURNS_RETAINED OSObject **a,
167 OS_RETURNS_RETAINED OSObject **b);
168
169void use_always_write_into_two_out_params() {
170 OSObject *obj1;
171 OSObject *obj2;
172 always_write_into_two_out_params(&obj1, &obj2);
173 obj1->release();
174 obj2->release();
175}
176
177void use_always_write_into_two_out_params_leak() {
178 OSObject *obj1;
179 OSObject *obj2;
180 always_write_into_two_out_params(&obj1, &obj2); // expected-note-re{{Call to function 'always_write_into_two_out_params' writes an OSObject of type 'OSObject' with a +1 retain count into an out parameter 'a'{{$}}}}
181 // expected-note-re@-1{{Call to function 'always_write_into_two_out_params' writes an OSObject of type 'OSObject' with a +1 retain count into an out parameter 'b'{{$}}}}
182} // expected-warning{{Potential leak of an object stored into 'obj1'}}
183 // expected-warning@-1{{Potential leak of an object stored into 'obj2'}}
184 // expected-note@-2{{Object leaked: object allocated and stored into 'obj1' is not referenced later in this execution path and has a retain count of +1}}
185 // expected-note@-3{{Object leaked: object allocated and stored into 'obj2' is not referenced later in this execution path and has a retain count of +1}}
186
187char *write_into_out_param_on_nonnull(OS_RETURNS_RETAINED OSObject **obj);
188
189void use_out_param_osreturn_on_nonnull() {
190 OSObject *obj;
191 if (write_into_out_param_on_nonnull(&obj)) {
192 obj->release();
193 }
194}
195
196void use_out_param_leak_osreturn_on_nonnull() {
197 OSObject *obj;
198 write_into_out_param_on_nonnull(&obj); // expected-note-re{{Call to function 'write_into_out_param_on_nonnull' writes an OSObject of type 'OSObject' with a +1 retain count into an out parameter 'obj' (assuming the call returns non-zero){{$}}}}
199} // expected-warning{{Potential leak of an object stored into 'obj'}}
200 // expected-note@-1{{Object leaked: object allocated and stored into 'obj' is not referenced later in this execution path and has a retain count of +1}}
201
202bool write_optional_out_param(OS_RETURNS_RETAINED OSObject **obj=nullptr);
203
204void use_optional_out_param() {
205 if (write_optional_out_param()) {};
206}
207
208OSReturn write_into_out_param_on_os_success(OS_RETURNS_RETAINED OSObject **obj);
209
210void write_into_non_retained_out_param(OS_RETURNS_NOT_RETAINED OSObject **obj);
211
212void use_write_into_non_retained_out_param() {
213 OSObject *obj;
214 write_into_non_retained_out_param(&obj);
215}
216
217void use_write_into_non_retained_out_param_uaf() {
218 OSObject *obj;
219 write_into_non_retained_out_param(&obj); // expected-note-re{{Call to function 'write_into_non_retained_out_param' writes an OSObject of type 'OSObject' with a +0 retain count into an out parameter 'obj'{{$}}}}
220 obj->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}
223
224void always_write_into_out_param(OS_RETURNS_RETAINED OSObject **obj);
225
226void pass_through_out_param(OSObject **obj) {
227 always_write_into_out_param(obj);
228}
229
230void always_write_into_out_param_has_source(OS_RETURNS_RETAINED OSObject **obj) {
231 *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
232}
233
234void use_always_write_into_out_param_has_source_leak() {
235 OSObject *obj;
236 always_write_into_out_param_has_source(&obj); // expected-note{{Calling 'always_write_into_out_param_has_source'}}
237 // expected-note@-1{{Returning from 'always_write_into_out_param_has_source'}}
238} // expected-warning{{Potential leak of an object stored into 'obj'}}
239 // expected-note@-1{{Object leaked: object allocated and stored into 'obj' is not referenced later in this execution path and has a retain count of +1}}
240
241void use_void_out_param_osreturn() {
242 OSObject *obj;
243 always_write_into_out_param(&obj);
244 obj->release();
245}
246
247void use_void_out_param_osreturn_leak() {
248 OSObject *obj;
249 always_write_into_out_param(&obj); // expected-note-re{{Call to function 'always_write_into_out_param' writes an OSObject of type 'OSObject' with a +1 retain count into an out parameter 'obj'{{$}}}}
250} // expected-warning{{Potential leak of an object stored into 'obj'}}
251 // expected-note@-1{{Object leaked: object allocated and stored into 'obj' is not referenced later in this execution path and has a retain count of +1}}
252
253void use_out_param_osreturn() {
254 OSObject *obj;
255 if (write_into_out_param_on_os_success(&obj) == kOSReturnSuccess) {
256 obj->release();
257 }
258}
259
260void use_out_param_leak_osreturn() {
261 OSObject *obj;
262 write_into_out_param_on_os_success(&obj); // expected-note-re{{Call to function 'write_into_out_param_on_os_success' writes an OSObject of type 'OSObject' with a +1 retain count into an out parameter 'obj' (assuming the call returns zero){{$}}}}
263} // expected-warning{{Potential leak of an object stored into 'obj'}}
264 // expected-note@-1{{Object leaked: object allocated and stored into 'obj' is not referenced later in this execution path and has a retain count of +1}}
265
266struct StructWithField {
267 OSObject *obj;
268
269 void initViaOutParamCall() { // no warning on writing into fields
270 always_write_into_out_param(&obj);
271 }
272
273};
274
George Karpenkovf5085322018-12-21 02:16:23 +0000275bool os_consume_violation_two_args(OS_CONSUME OSObject *obj, bool extra) {
276 if (coin()) { // expected-note{{Assuming the condition is false}}
277 // expected-note@-1{{Taking false branch}}
278 escape(obj);
279 return true;
280 }
George Karpenkov79f03402018-12-21 19:13:28 +0000281 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 +0000282}
283
George Karpenkovff014862018-12-11 01:13:40 +0000284bool os_consume_violation(OS_CONSUME OSObject *obj) {
285 if (coin()) { // expected-note{{Assuming the condition is false}}
286 // expected-note@-1{{Taking false branch}}
287 escape(obj);
288 return true;
289 }
George Karpenkov79f03402018-12-21 19:13:28 +0000290 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 +0000291}
292
293void os_consume_ok(OS_CONSUME OSObject *obj) {
294 escape(obj);
295}
296
297void use_os_consume_violation() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000298 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 +0000299 os_consume_violation(obj); // expected-note{{Calling 'os_consume_violation'}}
300 // expected-note@-1{{Returning from 'os_consume_violation'}}
301} // 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}}
302 // expected-warning@-1{{Potential leak of an object stored into 'obj'}}
303
George Karpenkovf5085322018-12-21 02:16:23 +0000304void use_os_consume_violation_two_args() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000305 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 +0000306 os_consume_violation_two_args(obj, coin()); // expected-note{{Calling 'os_consume_violation_two_args'}}
307 // expected-note@-1{{Returning from 'os_consume_violation_two_args'}}
308} // 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}}
309 // expected-warning@-1{{Potential leak of an object stored into 'obj'}}
310
George Karpenkovff014862018-12-11 01:13:40 +0000311void use_os_consume_ok() {
312 OSObject *obj = new OSObject;
313 os_consume_ok(obj);
314}
George Karpenkov041c9fa2018-12-08 01:18:40 +0000315
316void test_escaping_into_voidstar() {
317 OSObject *obj = new OSObject;
318 escape(obj);
319}
320
George Karpenkov255b0582018-12-21 19:13:40 +0000321void test_escape_has_source() {
322 OSObject *obj = new OSObject;
323 if (obj)
George Karpenkovd76cc592018-12-21 19:40:44 +0000324 escape_with_source(obj);
George Karpenkov255b0582018-12-21 19:13:40 +0000325 return;
326}
327
George Karpenkova71ec6c2018-12-06 22:06:44 +0000328void test_no_infinite_check_recursion(MyArray *arr) {
329 OSObject *input = new OSObject;
330 OSObject *o = arr->generateObject(input);
331 o->release();
332 input->release();
333}
334
335
George Karpenkova717bc72018-12-05 18:34:54 +0000336void check_param_attribute_propagation(MyArray *parent) {
337 OSArray *arr = new OSArray;
338 parent->consumeReference(arr);
339}
340
341unsigned int check_attribute_propagation(OSArray *arr) {
342 OSObject *other = arr->identity();
343 OSArray *casted = OSDynamicCast(OSArray, other);
344 if (casted)
345 return casted->getCount();
346 return 0;
347}
348
349unsigned int check_attribute_indirect_propagation(MyArray *arr) {
350 OSObject *other = arr->identity();
351 OSArray *casted = OSDynamicCast(OSArray, other);
352 if (casted)
353 return casted->getCount();
354 return 0;
355}
356
George Karpenkovb0b61952018-12-06 22:07:12 +0000357void check_consumes_this(OSArray *owner) {
358 OSArray *arr = new OSArray;
359 arr->putIntoArray(owner);
360}
361
362void check_consumes_this_with_template(OSArray *owner) {
363 OSArray *arr = new OSArray;
364 arr->putIntoT(owner);
365}
366
George Karpenkovbe3f4bd2018-11-30 20:43:42 +0000367void check_free_no_error() {
368 OSArray *arr = OSArray::withCapacity(10);
369 arr->retain();
370 arr->retain();
371 arr->retain();
372 arr->free();
373}
374
375void check_free_use_after_free() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000376 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 +0000377 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
378 arr->free(); // expected-note{{Object released}}
379 arr->retain(); // expected-warning{{Reference-counted object is used after it is released}}
380 // expected-note@-1{{Reference-counted object is used after it is released}}
381}
382
383unsigned int check_leak_explicit_new() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000384 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 +0000385 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}}
386 // expected-warning@-1{{Potential leak of an object stored into 'arr'}}
George Karpenkovbe3f4bd2018-11-30 20:43:42 +0000387}
388
389unsigned int check_leak_factory() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000390 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 +0000391 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}}
392 // expected-warning@-1{{Potential leak of an object stored into 'arr'}}
393}
394
George Karpenkov3bdbeb12018-11-30 02:18:10 +0000395void check_get_object() {
396 OSObject::getObject();
397}
398
399void check_Get_object() {
400 OSObject::GetObject();
401}
402
George Karpenkov83fb5362018-10-31 17:38:46 +0000403void check_custom_iterator_rule(OSArray *arr) {
404 OSIterator *it = arr->getIterator();
405 it->release();
406}
407
George Karpenkove2f09542018-11-30 02:17:57 +0000408void check_iterator_leak(OSArray *arr) {
George Karpenkov4f64b382019-01-10 18:15:57 +0000409 arr->getIterator(); // expected-note{{Call to method 'OSArray::getIterator' returns an OSObject of type 'OSIterator' with a +1 retain count}}
410} // expected-note{{Object leaked: allocated object of type 'OSIterator' is not referenced later}}
411 // expected-warning@-1{{Potential leak of an object of type 'OSIterator}}'
George Karpenkove2f09542018-11-30 02:17:57 +0000412
George Karpenkov081c4772018-10-23 23:11:50 +0000413void check_no_invalidation() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000414 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 +0000415 OtherStruct::doNothingToArray(arr);
416} // expected-warning{{Potential leak of an object stored into 'arr'}}
417 // expected-note@-1{{Object leaked}}
418
George Karpenkov3cfa04e2018-10-25 23:38:41 +0000419void check_no_invalidation_other_struct() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000420 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 +0000421 OtherStruct other(arr); // expected-warning{{Potential leak}}
422 // expected-note@-1{{Object leaked}}
423}
424
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000425struct ArrayOwner : public OSObject {
426 OSArray *arr;
427 ArrayOwner(OSArray *arr) : arr(arr) {}
428
429 static ArrayOwner* create(OSArray *arr) {
430 return new ArrayOwner(arr);
431 }
432
433 OSArray *getArray() {
434 return arr;
435 }
436
437 OSArray *createArray() {
438 return OSArray::withCapacity(10);
439 }
440
441 OSArray *createArraySourceUnknown();
442
443 OSArray *getArraySourceUnknown();
444};
445
George Karpenkova1c3bb82018-11-30 02:17:31 +0000446OSArray *generateArray() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000447 return OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}
448 // 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 +0000449}
450
451unsigned int check_leak_good_error_message() {
452 unsigned int out;
453 {
454 OSArray *leaked = generateArray(); // expected-note{{Calling 'generateArray'}}
455 // expected-note@-1{{Returning from 'generateArray'}}
456 out = leaked->getCount(); // expected-warning{{Potential leak of an object stored into 'leaked'}}
457 // 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}}
458 }
459 return out;
460}
461
462unsigned int check_leak_msg_temporary() {
George Karpenkovf893ea12018-11-30 02:17:44 +0000463 return generateArray()->getCount(); // expected-warning{{Potential leak of an object}}
464 // expected-note@-1{{Calling 'generateArray'}}
465 // expected-note@-2{{Returning from 'generateArray'}}
George Karpenkov4f64b382019-01-10 18:15:57 +0000466 // 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 +0000467}
468
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000469void check_confusing_getters() {
470 OSArray *arr = OSArray::withCapacity(10);
471
472 ArrayOwner *AO = ArrayOwner::create(arr);
473 AO->getArray();
474
475 AO->release();
476 arr->release();
477}
478
George Karpenkov081c4772018-10-23 23:11:50 +0000479void check_rc_consumed() {
480 OSArray *arr = OSArray::withCapacity(10);
481 OSArray::consumeArray(arr);
482}
483
484void check_rc_consume_temporary() {
485 OSArray::consumeArray(OSArray::withCapacity(10));
486}
487
488void check_rc_getter() {
489 OSArray *arr = OSArray::MaskedGetter();
490 (void)arr;
491}
492
493void check_rc_create() {
494 OSArray *arr = OSArray::getOoopsActuallyCreate();
495 arr->release();
496}
497
498
George Karpenkov41dc8de2018-10-11 22:59:16 +0000499void check_dynamic_cast() {
500 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1));
501 arr->release();
502}
503
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000504unsigned int check_dynamic_cast_no_null_on_orig(OSObject *obj) {
505 OSArray *arr = OSDynamicCast(OSArray, obj);
506 if (arr) {
507 return arr->getCount();
508 } else {
509
510 // The fact that dynamic cast has failed should not imply that
511 // the input object was null.
512 return obj->foo(); // no-warning
513 }
514}
515
516void check_dynamic_cast_null_branch(OSObject *obj) {
George Karpenkove2f09542018-11-30 02:17:57 +0000517 OSArray *arr1 = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000518 OSArray *arr = OSDynamicCast(OSArray, obj);
519 if (!arr) // expected-note{{Taking true branch}}
George Karpenkova1c3bb82018-11-30 02:17:31 +0000520 return; // expected-warning{{Potential leak of an object stored into 'arr1'}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000521 // expected-note@-1{{Object leaked}}
522 arr1->release();
523}
524
George Karpenkov41dc8de2018-10-11 22:59:16 +0000525void check_dynamic_cast_null_check() {
George Karpenkove2f09542018-11-30 02:17:57 +0000526 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); // expected-note{{Call to method 'OSObject::generateObject' returns an OSObject}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000527 // expected-warning@-1{{Potential leak of an object}}
528 // expected-note@-2{{Object leaked}}
George Karpenkov41dc8de2018-10-11 22:59:16 +0000529 if (!arr)
530 return;
531 arr->release();
532}
533
George Karpenkovab0011e2018-08-23 00:26:59 +0000534void use_after_release() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000535 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 +0000536 arr->release(); // expected-note{{Object released}}
537 arr->getCount(); // expected-warning{{Reference-counted object is used after it is released}}
538 // expected-note@-1{{Reference-counted object is used after it is released}}
539}
540
541void potential_leak() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000542 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 +0000543 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
544 arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}}
545 arr->getCount();
546} // expected-warning{{Potential leak of an object stored into 'arr'}}
547 // 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}}
548
549void proper_cleanup() {
550 OSArray *arr = OSArray::withCapacity(10); // +1
551 arr->retain(); // +2
552 arr->release(); // +1
553 arr->getCount();
554 arr->release(); // 0
555}
556
George Karpenkovab0011e2018-08-23 00:26:59 +0000557unsigned int no_warning_on_getter(ArrayOwner *owner) {
558 OSArray *arr = owner->getArray();
559 return arr->getCount();
560}
561
562unsigned int warn_on_overrelease(ArrayOwner *owner) {
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000563 // FIXME: summaries are not applied in case the source of the getter/setter
564 // is known.
565 // rdar://45681203
566 OSArray *arr = owner->getArray();
567 arr->release();
George Karpenkovab0011e2018-08-23 00:26:59 +0000568 return arr->getCount();
569}
570
571unsigned int nowarn_on_release_of_created(ArrayOwner *owner) {
572 OSArray *arr = owner->createArray();
573 unsigned int out = arr->getCount();
574 arr->release();
575 return out;
576}
577
578unsigned int nowarn_on_release_of_created_source_unknown(ArrayOwner *owner) {
579 OSArray *arr = owner->createArraySourceUnknown();
580 unsigned int out = arr->getCount();
581 arr->release();
582 return out;
583}
584
585unsigned int no_warn_ok_release(ArrayOwner *owner) {
586 OSArray *arr = owner->getArray(); // +0
587 arr->retain(); // +1
588 arr->release(); // +0
589 return arr->getCount(); // no-warning
590}
591
592unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) {
George Karpenkov4f64b382019-01-10 18:15:57 +0000593 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 +0000594 arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
595 // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
596 return arr->getCount();
597}
598
599unsigned int ok_release_with_unknown_source(ArrayOwner *owner) {
600 OSArray *arr = owner->getArraySourceUnknown(); // +0
601 arr->retain(); // +1
602 arr->release(); // +0
603 return arr->getCount();
604}
Artem Dergachev46f34622018-12-15 02:13:26 +0000605
606OSObject *getObject();
607typedef bool (^Blk)(OSObject *);
608
609void test_escape_to_unknown_block(Blk blk) {
610 blk(getObject()); // no-crash
611}