blob: 1e44866eff32467a929cb019f54af3d2d25b8ed6 [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
Vlad Tsyrklevichd5dd6a52019-01-18 08:43:22 +00004struct OSMetaClass;
5
6#define OS_CONSUME __attribute__((os_consumed))
7#define OS_RETURNS_RETAINED __attribute__((os_returns_retained))
8#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))
10#define OS_RETURNS_NOT_RETAINED __attribute__((os_returns_not_retained))
11#define OS_CONSUMES_THIS __attribute__((os_consumes_this))
12
13#define OSTypeID(type) (type::metaClass)
14
15#define OSDynamicCast(type, inst) \
16 ((type *) OSMetaClassBase::safeMetaCast((inst), OSTypeID(type)))
17
18using size_t = decltype(sizeof(int));
19
20struct OSObject {
21 virtual void retain();
22 virtual void release() {};
23 virtual void free();
24 virtual ~OSObject(){}
25
26 unsigned int foo() { return 42; }
27
28 virtual OS_RETURNS_NOT_RETAINED OSObject *identity();
29
30 static OSObject *generateObject(int);
31
32 static OSObject *getObject();
33 static OSObject *GetObject();
34
35 static void * operator new(size_t size);
36
37 static const OSMetaClass * const metaClass;
38};
George Karpenkovab0011e2018-08-23 00:26:59 +000039
George Karpenkov83fb5362018-10-31 17:38:46 +000040struct OSIterator : public OSObject {
Vlad Tsyrklevichd5dd6a52019-01-18 08:43:22 +000041
George Karpenkova1c3bb82018-11-30 02:17:31 +000042 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
Vlad Tsyrklevichd5dd6a52019-01-18 08:43:22 +000091struct OSMetaClassBase {
92 static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta);
93};
George Karpenkov41dc8de2018-10-11 22:59:16 +000094
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
George Karpenkov03391512019-01-16 23:21:38 +0000266void cleanup(OSObject **obj);
267
268void test_cleanup_escaping() {
269 __attribute__((cleanup(cleanup))) OSObject *obj;
270 always_write_into_out_param(&obj); // no-warning, the value has escaped.
271}
272
George Karpenkov5be959c2019-01-11 23:35:17 +0000273struct StructWithField {
274 OSObject *obj;
275
276 void initViaOutParamCall() { // no warning on writing into fields
277 always_write_into_out_param(&obj);
278 }
279
280};
281
George Karpenkovf5085322018-12-21 02:16:23 +0000282bool os_consume_violation_two_args(OS_CONSUME OSObject *obj, bool extra) {
283 if (coin()) { // expected-note{{Assuming the condition is false}}
284 // expected-note@-1{{Taking false branch}}
285 escape(obj);
286 return true;
287 }
George Karpenkov79f03402018-12-21 19:13:28 +0000288 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 +0000289}
290
George Karpenkovff014862018-12-11 01:13:40 +0000291bool os_consume_violation(OS_CONSUME OSObject *obj) {
292 if (coin()) { // expected-note{{Assuming the condition is false}}
293 // expected-note@-1{{Taking false branch}}
294 escape(obj);
295 return true;
296 }
George Karpenkov79f03402018-12-21 19:13:28 +0000297 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 +0000298}
299
300void os_consume_ok(OS_CONSUME OSObject *obj) {
301 escape(obj);
302}
303
304void use_os_consume_violation() {
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 Karpenkovff014862018-12-11 01:13:40 +0000306 os_consume_violation(obj); // expected-note{{Calling 'os_consume_violation'}}
307 // expected-note@-1{{Returning from 'os_consume_violation'}}
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 Karpenkovf5085322018-12-21 02:16:23 +0000311void use_os_consume_violation_two_args() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000312 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 +0000313 os_consume_violation_two_args(obj, coin()); // expected-note{{Calling 'os_consume_violation_two_args'}}
314 // expected-note@-1{{Returning from 'os_consume_violation_two_args'}}
315} // 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}}
316 // expected-warning@-1{{Potential leak of an object stored into 'obj'}}
317
George Karpenkovff014862018-12-11 01:13:40 +0000318void use_os_consume_ok() {
319 OSObject *obj = new OSObject;
320 os_consume_ok(obj);
321}
George Karpenkov041c9fa2018-12-08 01:18:40 +0000322
323void test_escaping_into_voidstar() {
324 OSObject *obj = new OSObject;
325 escape(obj);
326}
327
George Karpenkov255b0582018-12-21 19:13:40 +0000328void test_escape_has_source() {
329 OSObject *obj = new OSObject;
330 if (obj)
George Karpenkovd76cc592018-12-21 19:40:44 +0000331 escape_with_source(obj);
George Karpenkov255b0582018-12-21 19:13:40 +0000332 return;
333}
334
George Karpenkova71ec6c2018-12-06 22:06:44 +0000335void test_no_infinite_check_recursion(MyArray *arr) {
336 OSObject *input = new OSObject;
337 OSObject *o = arr->generateObject(input);
338 o->release();
339 input->release();
340}
341
342
George Karpenkova717bc72018-12-05 18:34:54 +0000343void check_param_attribute_propagation(MyArray *parent) {
344 OSArray *arr = new OSArray;
345 parent->consumeReference(arr);
346}
347
348unsigned int check_attribute_propagation(OSArray *arr) {
349 OSObject *other = arr->identity();
350 OSArray *casted = OSDynamicCast(OSArray, other);
351 if (casted)
352 return casted->getCount();
353 return 0;
354}
355
356unsigned int check_attribute_indirect_propagation(MyArray *arr) {
357 OSObject *other = arr->identity();
358 OSArray *casted = OSDynamicCast(OSArray, other);
359 if (casted)
360 return casted->getCount();
361 return 0;
362}
363
George Karpenkovb0b61952018-12-06 22:07:12 +0000364void check_consumes_this(OSArray *owner) {
365 OSArray *arr = new OSArray;
366 arr->putIntoArray(owner);
367}
368
369void check_consumes_this_with_template(OSArray *owner) {
370 OSArray *arr = new OSArray;
371 arr->putIntoT(owner);
372}
373
George Karpenkovbe3f4bd2018-11-30 20:43:42 +0000374void check_free_no_error() {
375 OSArray *arr = OSArray::withCapacity(10);
376 arr->retain();
377 arr->retain();
378 arr->retain();
379 arr->free();
380}
381
382void check_free_use_after_free() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000383 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 +0000384 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
385 arr->free(); // expected-note{{Object released}}
386 arr->retain(); // expected-warning{{Reference-counted object is used after it is released}}
387 // expected-note@-1{{Reference-counted object is used after it is released}}
388}
389
390unsigned int check_leak_explicit_new() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000391 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 +0000392 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}}
393 // expected-warning@-1{{Potential leak of an object stored into 'arr'}}
George Karpenkovbe3f4bd2018-11-30 20:43:42 +0000394}
395
396unsigned int check_leak_factory() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000397 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 +0000398 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}}
399 // expected-warning@-1{{Potential leak of an object stored into 'arr'}}
400}
401
George Karpenkov3bdbeb12018-11-30 02:18:10 +0000402void check_get_object() {
403 OSObject::getObject();
404}
405
406void check_Get_object() {
407 OSObject::GetObject();
408}
409
George Karpenkov83fb5362018-10-31 17:38:46 +0000410void check_custom_iterator_rule(OSArray *arr) {
411 OSIterator *it = arr->getIterator();
412 it->release();
413}
414
George Karpenkove2f09542018-11-30 02:17:57 +0000415void check_iterator_leak(OSArray *arr) {
George Karpenkov4f64b382019-01-10 18:15:57 +0000416 arr->getIterator(); // expected-note{{Call to method 'OSArray::getIterator' returns an OSObject of type 'OSIterator' with a +1 retain count}}
417} // expected-note{{Object leaked: allocated object of type 'OSIterator' is not referenced later}}
418 // expected-warning@-1{{Potential leak of an object of type 'OSIterator}}'
George Karpenkove2f09542018-11-30 02:17:57 +0000419
George Karpenkov081c4772018-10-23 23:11:50 +0000420void check_no_invalidation() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000421 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 +0000422 OtherStruct::doNothingToArray(arr);
423} // expected-warning{{Potential leak of an object stored into 'arr'}}
424 // expected-note@-1{{Object leaked}}
425
George Karpenkov3cfa04e2018-10-25 23:38:41 +0000426void check_no_invalidation_other_struct() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000427 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 +0000428 OtherStruct other(arr); // expected-warning{{Potential leak}}
429 // expected-note@-1{{Object leaked}}
430}
431
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000432struct ArrayOwner : public OSObject {
433 OSArray *arr;
434 ArrayOwner(OSArray *arr) : arr(arr) {}
435
436 static ArrayOwner* create(OSArray *arr) {
437 return new ArrayOwner(arr);
438 }
439
440 OSArray *getArray() {
441 return arr;
442 }
443
444 OSArray *createArray() {
445 return OSArray::withCapacity(10);
446 }
447
448 OSArray *createArraySourceUnknown();
449
450 OSArray *getArraySourceUnknown();
451};
452
George Karpenkova1c3bb82018-11-30 02:17:31 +0000453OSArray *generateArray() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000454 return OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}
455 // 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 +0000456}
457
458unsigned int check_leak_good_error_message() {
459 unsigned int out;
460 {
461 OSArray *leaked = generateArray(); // expected-note{{Calling 'generateArray'}}
462 // expected-note@-1{{Returning from 'generateArray'}}
463 out = leaked->getCount(); // expected-warning{{Potential leak of an object stored into 'leaked'}}
464 // 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}}
465 }
466 return out;
467}
468
469unsigned int check_leak_msg_temporary() {
George Karpenkovf893ea12018-11-30 02:17:44 +0000470 return generateArray()->getCount(); // expected-warning{{Potential leak of an object}}
471 // expected-note@-1{{Calling 'generateArray'}}
472 // expected-note@-2{{Returning from 'generateArray'}}
George Karpenkov4f64b382019-01-10 18:15:57 +0000473 // 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 +0000474}
475
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000476void check_confusing_getters() {
477 OSArray *arr = OSArray::withCapacity(10);
478
479 ArrayOwner *AO = ArrayOwner::create(arr);
480 AO->getArray();
481
482 AO->release();
483 arr->release();
484}
485
George Karpenkov081c4772018-10-23 23:11:50 +0000486void check_rc_consumed() {
487 OSArray *arr = OSArray::withCapacity(10);
488 OSArray::consumeArray(arr);
489}
490
491void check_rc_consume_temporary() {
492 OSArray::consumeArray(OSArray::withCapacity(10));
493}
494
495void check_rc_getter() {
496 OSArray *arr = OSArray::MaskedGetter();
497 (void)arr;
498}
499
500void check_rc_create() {
501 OSArray *arr = OSArray::getOoopsActuallyCreate();
502 arr->release();
503}
504
505
George Karpenkov41dc8de2018-10-11 22:59:16 +0000506void check_dynamic_cast() {
507 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1));
508 arr->release();
509}
510
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000511unsigned int check_dynamic_cast_no_null_on_orig(OSObject *obj) {
512 OSArray *arr = OSDynamicCast(OSArray, obj);
513 if (arr) {
514 return arr->getCount();
515 } else {
516
517 // The fact that dynamic cast has failed should not imply that
518 // the input object was null.
519 return obj->foo(); // no-warning
520 }
521}
522
523void check_dynamic_cast_null_branch(OSObject *obj) {
George Karpenkove2f09542018-11-30 02:17:57 +0000524 OSArray *arr1 = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000525 OSArray *arr = OSDynamicCast(OSArray, obj);
526 if (!arr) // expected-note{{Taking true branch}}
George Karpenkova1c3bb82018-11-30 02:17:31 +0000527 return; // expected-warning{{Potential leak of an object stored into 'arr1'}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000528 // expected-note@-1{{Object leaked}}
529 arr1->release();
530}
531
George Karpenkov41dc8de2018-10-11 22:59:16 +0000532void check_dynamic_cast_null_check() {
George Karpenkove2f09542018-11-30 02:17:57 +0000533 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); // expected-note{{Call to method 'OSObject::generateObject' returns an OSObject}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000534 // expected-warning@-1{{Potential leak of an object}}
535 // expected-note@-2{{Object leaked}}
George Karpenkov41dc8de2018-10-11 22:59:16 +0000536 if (!arr)
537 return;
538 arr->release();
539}
540
George Karpenkovab0011e2018-08-23 00:26:59 +0000541void use_after_release() {
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->release(); // expected-note{{Object released}}
544 arr->getCount(); // expected-warning{{Reference-counted object is used after it is released}}
545 // expected-note@-1{{Reference-counted object is used after it is released}}
546}
547
548void potential_leak() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000549 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 +0000550 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
551 arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}}
552 arr->getCount();
553} // expected-warning{{Potential leak of an object stored into 'arr'}}
554 // 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}}
555
556void proper_cleanup() {
557 OSArray *arr = OSArray::withCapacity(10); // +1
558 arr->retain(); // +2
559 arr->release(); // +1
560 arr->getCount();
561 arr->release(); // 0
562}
563
George Karpenkovab0011e2018-08-23 00:26:59 +0000564unsigned int no_warning_on_getter(ArrayOwner *owner) {
565 OSArray *arr = owner->getArray();
566 return arr->getCount();
567}
568
569unsigned int warn_on_overrelease(ArrayOwner *owner) {
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000570 // FIXME: summaries are not applied in case the source of the getter/setter
571 // is known.
572 // rdar://45681203
573 OSArray *arr = owner->getArray();
574 arr->release();
George Karpenkovab0011e2018-08-23 00:26:59 +0000575 return arr->getCount();
576}
577
578unsigned int nowarn_on_release_of_created(ArrayOwner *owner) {
579 OSArray *arr = owner->createArray();
580 unsigned int out = arr->getCount();
581 arr->release();
582 return out;
583}
584
585unsigned int nowarn_on_release_of_created_source_unknown(ArrayOwner *owner) {
586 OSArray *arr = owner->createArraySourceUnknown();
587 unsigned int out = arr->getCount();
588 arr->release();
589 return out;
590}
591
592unsigned int no_warn_ok_release(ArrayOwner *owner) {
593 OSArray *arr = owner->getArray(); // +0
594 arr->retain(); // +1
595 arr->release(); // +0
596 return arr->getCount(); // no-warning
597}
598
599unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) {
George Karpenkov4f64b382019-01-10 18:15:57 +0000600 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 +0000601 arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
602 // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
603 return arr->getCount();
604}
605
606unsigned int ok_release_with_unknown_source(ArrayOwner *owner) {
607 OSArray *arr = owner->getArraySourceUnknown(); // +0
608 arr->retain(); // +1
609 arr->release(); // +0
610 return arr->getCount();
611}
Artem Dergachev46f34622018-12-15 02:13:26 +0000612
613OSObject *getObject();
614typedef bool (^Blk)(OSObject *);
615
616void test_escape_to_unknown_block(Blk blk) {
617 blk(getObject()); // no-crash
618}