blob: 6cd7eb6d9af31cc194858aedcc0b632903675530 [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 Karpenkov2c2d0b62019-01-18 19:24:55 +00004#include "os_object_base.h"
5#include "os_smart_ptr.h"
George Karpenkovab0011e2018-08-23 00:26:59 +00006
George Karpenkov83fb5362018-10-31 17:38:46 +00007struct OSIterator : public OSObject {
George Karpenkova1c3bb82018-11-30 02:17:31 +00008 static const OSMetaClass * const metaClass;
George Karpenkov83fb5362018-10-31 17:38:46 +00009};
10
George Karpenkovab0011e2018-08-23 00:26:59 +000011struct OSArray : public OSObject {
12 unsigned int getCount();
13
George Karpenkova717bc72018-12-05 18:34:54 +000014 OSIterator * getIterator();
15
16 OSObject *identity() override;
17
George Karpenkova71ec6c2018-12-06 22:06:44 +000018 virtual OSObject *generateObject(OSObject *input);
19
George Karpenkova717bc72018-12-05 18:34:54 +000020 virtual void consumeReference(OS_CONSUME OSArray *other);
21
George Karpenkovb0b61952018-12-06 22:07:12 +000022 void putIntoArray(OSArray *array) OS_CONSUMES_THIS;
23
24 template <typename T>
25 void putIntoT(T *owner) OS_CONSUMES_THIS;
26
George Karpenkov62db8862018-11-30 02:18:23 +000027 static OSArray *generateArrayHasCode() {
28 return new OSArray;
29 }
30
George Karpenkovab0011e2018-08-23 00:26:59 +000031 static OSArray *withCapacity(unsigned int capacity);
George Karpenkov081c4772018-10-23 23:11:50 +000032 static void consumeArray(OS_CONSUME OSArray * array);
33
34 static OSArray* consumeArrayHasCode(OS_CONSUME OSArray * array) {
35 return nullptr;
36 }
37
38 static OS_RETURNS_NOT_RETAINED OSArray *MaskedGetter();
39 static OS_RETURNS_RETAINED OSArray *getOoopsActuallyCreate();
40
George Karpenkov41dc8de2018-10-11 22:59:16 +000041 static const OSMetaClass * const metaClass;
George Karpenkovab0011e2018-08-23 00:26:59 +000042};
43
George Karpenkova717bc72018-12-05 18:34:54 +000044struct MyArray : public OSArray {
45 void consumeReference(OSArray *other) override;
46
47 OSObject *identity() override;
George Karpenkova71ec6c2018-12-06 22:06:44 +000048
49 OSObject *generateObject(OSObject *input) override;
George Karpenkova717bc72018-12-05 18:34:54 +000050};
51
George Karpenkov081c4772018-10-23 23:11:50 +000052struct OtherStruct {
53 static void doNothingToArray(OSArray *array);
George Karpenkov3cfa04e2018-10-25 23:38:41 +000054 OtherStruct(OSArray *arr);
George Karpenkov081c4772018-10-23 23:11:50 +000055};
56
George Karpenkovdb0c66e2019-01-22 19:50:47 +000057bool test_meta_cast_no_leak(OSMetaClassBase *arg) {
58 return arg && arg->metaCast("blah") != nullptr;
59}
George Karpenkov41dc8de2018-10-11 22:59:16 +000060
George Karpenkov041c9fa2018-12-08 01:18:40 +000061void escape(void *);
George Karpenkov255b0582018-12-21 19:13:40 +000062void escape_with_source(void *p) {}
George Karpenkovff014862018-12-11 01:13:40 +000063bool coin();
64
George Karpenkov5be959c2019-01-11 23:35:17 +000065typedef int kern_return_t;
66typedef kern_return_t IOReturn;
67typedef kern_return_t OSReturn;
68#define kOSReturnSuccess 0
69#define kIOReturnSuccess 0
70
71bool write_into_out_param_on_success(OS_RETURNS_RETAINED OSObject **obj);
72
73void use_out_param() {
74 OSObject *obj;
75 if (write_into_out_param_on_success(&obj)) {
76 obj->release();
77 }
78}
79
80void use_out_param_leak() {
81 OSObject *obj;
82 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){{$}}}}
83} // expected-warning{{Potential leak of an object stored into 'obj'}}
84 // 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}}
85
86bool write_into_out_param_on_failure(OS_RETURNS_RETAINED_ON_ZERO OSObject **obj);
87
88void use_out_param_leak2() {
89 OSObject *obj;
90 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){{$}}}}
91} // expected-warning{{Potential leak of an object stored into 'obj'}}
92 // 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}}
93
94void use_out_param_on_failure() {
95 OSObject *obj;
96 if (!write_into_out_param_on_failure(&obj)) {
97 obj->release();
98 }
99}
100
101IOReturn write_into_out_param_on_nonzero(OS_RETURNS_RETAINED_ON_NONZERO OSObject **obj);
102
103void use_out_param_on_nonzero() {
104 OSObject *obj;
105 if (write_into_out_param_on_nonzero(&obj) != kIOReturnSuccess) {
106 obj->release();
107 }
108}
109
110bool write_into_two_out_params(OS_RETURNS_RETAINED OSObject **a,
111 OS_RETURNS_RETAINED OSObject **b);
112
113void use_write_into_two_out_params() {
114 OSObject *obj1;
115 OSObject *obj2;
116 if (write_into_two_out_params(&obj1, &obj2)) {
117 obj1->release();
118 obj2->release();
119 }
120}
121
122void use_write_two_out_params_leak() {
123 OSObject *obj1;
124 OSObject *obj2;
125 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){{$}}}}
126 // 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){{$}}}}
127} // expected-warning{{Potential leak of an object stored into 'obj1'}}
128 // expected-warning@-1{{Potential leak of an object stored into 'obj2'}}
129 // 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}}
130 // 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}}
131
132void always_write_into_two_out_params(OS_RETURNS_RETAINED OSObject **a,
133 OS_RETURNS_RETAINED OSObject **b);
134
135void use_always_write_into_two_out_params() {
136 OSObject *obj1;
137 OSObject *obj2;
138 always_write_into_two_out_params(&obj1, &obj2);
139 obj1->release();
140 obj2->release();
141}
142
143void use_always_write_into_two_out_params_leak() {
144 OSObject *obj1;
145 OSObject *obj2;
146 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'{{$}}}}
147 // 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'{{$}}}}
148} // expected-warning{{Potential leak of an object stored into 'obj1'}}
149 // expected-warning@-1{{Potential leak of an object stored into 'obj2'}}
150 // 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}}
151 // 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}}
152
153char *write_into_out_param_on_nonnull(OS_RETURNS_RETAINED OSObject **obj);
154
155void use_out_param_osreturn_on_nonnull() {
156 OSObject *obj;
157 if (write_into_out_param_on_nonnull(&obj)) {
158 obj->release();
159 }
160}
161
162void use_out_param_leak_osreturn_on_nonnull() {
163 OSObject *obj;
164 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){{$}}}}
165} // expected-warning{{Potential leak of an object stored into 'obj'}}
166 // 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}}
167
168bool write_optional_out_param(OS_RETURNS_RETAINED OSObject **obj=nullptr);
169
170void use_optional_out_param() {
171 if (write_optional_out_param()) {};
172}
173
174OSReturn write_into_out_param_on_os_success(OS_RETURNS_RETAINED OSObject **obj);
175
176void write_into_non_retained_out_param(OS_RETURNS_NOT_RETAINED OSObject **obj);
177
178void use_write_into_non_retained_out_param() {
179 OSObject *obj;
180 write_into_non_retained_out_param(&obj);
181}
182
183void use_write_into_non_retained_out_param_uaf() {
184 OSObject *obj;
185 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'{{$}}}}
186 obj->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
187 // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
188}
189
190void always_write_into_out_param(OS_RETURNS_RETAINED OSObject **obj);
191
192void pass_through_out_param(OSObject **obj) {
193 always_write_into_out_param(obj);
194}
195
196void always_write_into_out_param_has_source(OS_RETURNS_RETAINED OSObject **obj) {
197 *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
198}
199
200void use_always_write_into_out_param_has_source_leak() {
201 OSObject *obj;
202 always_write_into_out_param_has_source(&obj); // expected-note{{Calling 'always_write_into_out_param_has_source'}}
203 // expected-note@-1{{Returning from 'always_write_into_out_param_has_source'}}
204} // expected-warning{{Potential leak of an object stored into 'obj'}}
205 // 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}}
206
207void use_void_out_param_osreturn() {
208 OSObject *obj;
209 always_write_into_out_param(&obj);
210 obj->release();
211}
212
213void use_void_out_param_osreturn_leak() {
214 OSObject *obj;
215 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'{{$}}}}
216} // expected-warning{{Potential leak of an object stored into 'obj'}}
217 // 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}}
218
219void use_out_param_osreturn() {
220 OSObject *obj;
221 if (write_into_out_param_on_os_success(&obj) == kOSReturnSuccess) {
222 obj->release();
223 }
224}
225
226void use_out_param_leak_osreturn() {
227 OSObject *obj;
228 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){{$}}}}
229} // expected-warning{{Potential leak of an object stored into 'obj'}}
230 // 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}}
231
George Karpenkov03391512019-01-16 23:21:38 +0000232void cleanup(OSObject **obj);
233
234void test_cleanup_escaping() {
235 __attribute__((cleanup(cleanup))) OSObject *obj;
236 always_write_into_out_param(&obj); // no-warning, the value has escaped.
237}
238
George Karpenkov5be959c2019-01-11 23:35:17 +0000239struct StructWithField {
240 OSObject *obj;
241
242 void initViaOutParamCall() { // no warning on writing into fields
243 always_write_into_out_param(&obj);
244 }
245
246};
247
George Karpenkovf5085322018-12-21 02:16:23 +0000248bool os_consume_violation_two_args(OS_CONSUME OSObject *obj, bool extra) {
249 if (coin()) { // expected-note{{Assuming the condition is false}}
250 // expected-note@-1{{Taking false branch}}
251 escape(obj);
252 return true;
253 }
George Karpenkov79f03402018-12-21 19:13:28 +0000254 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 +0000255}
256
George Karpenkovff014862018-12-11 01:13:40 +0000257bool os_consume_violation(OS_CONSUME OSObject *obj) {
258 if (coin()) { // expected-note{{Assuming the condition is false}}
259 // expected-note@-1{{Taking false branch}}
260 escape(obj);
261 return true;
262 }
George Karpenkov79f03402018-12-21 19:13:28 +0000263 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 +0000264}
265
266void os_consume_ok(OS_CONSUME OSObject *obj) {
267 escape(obj);
268}
269
270void use_os_consume_violation() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000271 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 +0000272 os_consume_violation(obj); // expected-note{{Calling 'os_consume_violation'}}
273 // expected-note@-1{{Returning from 'os_consume_violation'}}
274} // 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}}
275 // expected-warning@-1{{Potential leak of an object stored into 'obj'}}
276
George Karpenkovf5085322018-12-21 02:16:23 +0000277void use_os_consume_violation_two_args() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000278 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 +0000279 os_consume_violation_two_args(obj, coin()); // expected-note{{Calling 'os_consume_violation_two_args'}}
280 // expected-note@-1{{Returning from 'os_consume_violation_two_args'}}
281} // 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}}
282 // expected-warning@-1{{Potential leak of an object stored into 'obj'}}
283
George Karpenkovff014862018-12-11 01:13:40 +0000284void use_os_consume_ok() {
285 OSObject *obj = new OSObject;
286 os_consume_ok(obj);
287}
George Karpenkov041c9fa2018-12-08 01:18:40 +0000288
289void test_escaping_into_voidstar() {
290 OSObject *obj = new OSObject;
291 escape(obj);
292}
293
George Karpenkov255b0582018-12-21 19:13:40 +0000294void test_escape_has_source() {
295 OSObject *obj = new OSObject;
296 if (obj)
George Karpenkovd76cc592018-12-21 19:40:44 +0000297 escape_with_source(obj);
George Karpenkov255b0582018-12-21 19:13:40 +0000298 return;
299}
300
George Karpenkova71ec6c2018-12-06 22:06:44 +0000301void test_no_infinite_check_recursion(MyArray *arr) {
302 OSObject *input = new OSObject;
303 OSObject *o = arr->generateObject(input);
304 o->release();
305 input->release();
306}
307
308
George Karpenkova717bc72018-12-05 18:34:54 +0000309void check_param_attribute_propagation(MyArray *parent) {
310 OSArray *arr = new OSArray;
311 parent->consumeReference(arr);
312}
313
314unsigned int check_attribute_propagation(OSArray *arr) {
315 OSObject *other = arr->identity();
316 OSArray *casted = OSDynamicCast(OSArray, other);
317 if (casted)
318 return casted->getCount();
319 return 0;
320}
321
322unsigned int check_attribute_indirect_propagation(MyArray *arr) {
323 OSObject *other = arr->identity();
324 OSArray *casted = OSDynamicCast(OSArray, other);
325 if (casted)
326 return casted->getCount();
327 return 0;
328}
329
George Karpenkovb0b61952018-12-06 22:07:12 +0000330void check_consumes_this(OSArray *owner) {
331 OSArray *arr = new OSArray;
332 arr->putIntoArray(owner);
333}
334
335void check_consumes_this_with_template(OSArray *owner) {
336 OSArray *arr = new OSArray;
337 arr->putIntoT(owner);
338}
339
George Karpenkovbe3f4bd2018-11-30 20:43:42 +0000340void check_free_no_error() {
341 OSArray *arr = OSArray::withCapacity(10);
342 arr->retain();
343 arr->retain();
344 arr->retain();
345 arr->free();
346}
347
348void check_free_use_after_free() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000349 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 +0000350 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
351 arr->free(); // expected-note{{Object released}}
352 arr->retain(); // expected-warning{{Reference-counted object is used after it is released}}
353 // expected-note@-1{{Reference-counted object is used after it is released}}
354}
355
356unsigned int check_leak_explicit_new() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000357 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 +0000358 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}}
359 // expected-warning@-1{{Potential leak of an object stored into 'arr'}}
George Karpenkovbe3f4bd2018-11-30 20:43:42 +0000360}
361
362unsigned int check_leak_factory() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000363 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 +0000364 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}}
365 // expected-warning@-1{{Potential leak of an object stored into 'arr'}}
366}
367
George Karpenkov3bdbeb12018-11-30 02:18:10 +0000368void check_get_object() {
369 OSObject::getObject();
370}
371
372void check_Get_object() {
373 OSObject::GetObject();
374}
375
George Karpenkov83fb5362018-10-31 17:38:46 +0000376void check_custom_iterator_rule(OSArray *arr) {
377 OSIterator *it = arr->getIterator();
378 it->release();
379}
380
George Karpenkove2f09542018-11-30 02:17:57 +0000381void check_iterator_leak(OSArray *arr) {
George Karpenkov4f64b382019-01-10 18:15:57 +0000382 arr->getIterator(); // expected-note{{Call to method 'OSArray::getIterator' returns an OSObject of type 'OSIterator' with a +1 retain count}}
383} // expected-note{{Object leaked: allocated object of type 'OSIterator' is not referenced later}}
384 // expected-warning@-1{{Potential leak of an object of type 'OSIterator}}'
George Karpenkove2f09542018-11-30 02:17:57 +0000385
George Karpenkov081c4772018-10-23 23:11:50 +0000386void check_no_invalidation() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000387 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 +0000388 OtherStruct::doNothingToArray(arr);
389} // expected-warning{{Potential leak of an object stored into 'arr'}}
390 // expected-note@-1{{Object leaked}}
391
George Karpenkov3cfa04e2018-10-25 23:38:41 +0000392void check_no_invalidation_other_struct() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000393 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 +0000394 OtherStruct other(arr); // expected-warning{{Potential leak}}
395 // expected-note@-1{{Object leaked}}
396}
397
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000398struct ArrayOwner : public OSObject {
399 OSArray *arr;
400 ArrayOwner(OSArray *arr) : arr(arr) {}
401
402 static ArrayOwner* create(OSArray *arr) {
403 return new ArrayOwner(arr);
404 }
405
406 OSArray *getArray() {
407 return arr;
408 }
409
410 OSArray *createArray() {
411 return OSArray::withCapacity(10);
412 }
413
414 OSArray *createArraySourceUnknown();
415
416 OSArray *getArraySourceUnknown();
417};
418
George Karpenkova1c3bb82018-11-30 02:17:31 +0000419OSArray *generateArray() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000420 return OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}
421 // 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 +0000422}
423
424unsigned int check_leak_good_error_message() {
425 unsigned int out;
426 {
427 OSArray *leaked = generateArray(); // expected-note{{Calling 'generateArray'}}
428 // expected-note@-1{{Returning from 'generateArray'}}
429 out = leaked->getCount(); // expected-warning{{Potential leak of an object stored into 'leaked'}}
430 // 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}}
431 }
432 return out;
433}
434
435unsigned int check_leak_msg_temporary() {
George Karpenkovf893ea12018-11-30 02:17:44 +0000436 return generateArray()->getCount(); // expected-warning{{Potential leak of an object}}
437 // expected-note@-1{{Calling 'generateArray'}}
438 // expected-note@-2{{Returning from 'generateArray'}}
George Karpenkov4f64b382019-01-10 18:15:57 +0000439 // 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 +0000440}
441
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000442void check_confusing_getters() {
443 OSArray *arr = OSArray::withCapacity(10);
444
445 ArrayOwner *AO = ArrayOwner::create(arr);
446 AO->getArray();
447
448 AO->release();
449 arr->release();
450}
451
George Karpenkov081c4772018-10-23 23:11:50 +0000452void check_rc_consumed() {
453 OSArray *arr = OSArray::withCapacity(10);
454 OSArray::consumeArray(arr);
455}
456
457void check_rc_consume_temporary() {
458 OSArray::consumeArray(OSArray::withCapacity(10));
459}
460
461void check_rc_getter() {
462 OSArray *arr = OSArray::MaskedGetter();
463 (void)arr;
464}
465
466void check_rc_create() {
467 OSArray *arr = OSArray::getOoopsActuallyCreate();
468 arr->release();
469}
470
471
George Karpenkov41dc8de2018-10-11 22:59:16 +0000472void check_dynamic_cast() {
473 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1));
474 arr->release();
475}
476
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000477unsigned int check_dynamic_cast_no_null_on_orig(OSObject *obj) {
478 OSArray *arr = OSDynamicCast(OSArray, obj);
479 if (arr) {
480 return arr->getCount();
481 } else {
482
483 // The fact that dynamic cast has failed should not imply that
484 // the input object was null.
485 return obj->foo(); // no-warning
486 }
487}
488
489void check_dynamic_cast_null_branch(OSObject *obj) {
George Karpenkove2f09542018-11-30 02:17:57 +0000490 OSArray *arr1 = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject}}
George Karpenkova9e29562019-01-22 19:51:00 +0000491 OSArray *arr = OSDynamicCast(OSArray, obj); // expected-note{{Assuming dynamic cast returns null due to type mismatch}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000492 if (!arr) // expected-note{{Taking true branch}}
George Karpenkova1c3bb82018-11-30 02:17:31 +0000493 return; // expected-warning{{Potential leak of an object stored into 'arr1'}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000494 // expected-note@-1{{Object leaked}}
495 arr1->release();
496}
497
George Karpenkov41dc8de2018-10-11 22:59:16 +0000498void check_dynamic_cast_null_check() {
George Karpenkove2f09542018-11-30 02:17:57 +0000499 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); // expected-note{{Call to method 'OSObject::generateObject' returns an OSObject}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000500 // expected-warning@-1{{Potential leak of an object}}
501 // expected-note@-2{{Object leaked}}
George Karpenkova9e29562019-01-22 19:51:00 +0000502 // expected-note@-3{{Assuming dynamic cast returns null due to type mismatch}}
George Karpenkov41dc8de2018-10-11 22:59:16 +0000503 if (!arr)
504 return;
505 arr->release();
506}
507
George Karpenkovab0011e2018-08-23 00:26:59 +0000508void use_after_release() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000509 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 +0000510 arr->release(); // expected-note{{Object released}}
511 arr->getCount(); // expected-warning{{Reference-counted object is used after it is released}}
512 // expected-note@-1{{Reference-counted object is used after it is released}}
513}
514
515void potential_leak() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000516 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 +0000517 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
518 arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}}
519 arr->getCount();
520} // expected-warning{{Potential leak of an object stored into 'arr'}}
521 // 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}}
522
523void proper_cleanup() {
524 OSArray *arr = OSArray::withCapacity(10); // +1
525 arr->retain(); // +2
526 arr->release(); // +1
527 arr->getCount();
528 arr->release(); // 0
529}
530
George Karpenkovab0011e2018-08-23 00:26:59 +0000531unsigned int no_warning_on_getter(ArrayOwner *owner) {
532 OSArray *arr = owner->getArray();
533 return arr->getCount();
534}
535
536unsigned int warn_on_overrelease(ArrayOwner *owner) {
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000537 // FIXME: summaries are not applied in case the source of the getter/setter
538 // is known.
539 // rdar://45681203
540 OSArray *arr = owner->getArray();
541 arr->release();
George Karpenkovab0011e2018-08-23 00:26:59 +0000542 return arr->getCount();
543}
544
545unsigned int nowarn_on_release_of_created(ArrayOwner *owner) {
546 OSArray *arr = owner->createArray();
547 unsigned int out = arr->getCount();
548 arr->release();
549 return out;
550}
551
552unsigned int nowarn_on_release_of_created_source_unknown(ArrayOwner *owner) {
553 OSArray *arr = owner->createArraySourceUnknown();
554 unsigned int out = arr->getCount();
555 arr->release();
556 return out;
557}
558
559unsigned int no_warn_ok_release(ArrayOwner *owner) {
560 OSArray *arr = owner->getArray(); // +0
561 arr->retain(); // +1
562 arr->release(); // +0
563 return arr->getCount(); // no-warning
564}
565
566unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) {
George Karpenkov4f64b382019-01-10 18:15:57 +0000567 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 +0000568 arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
569 // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
570 return arr->getCount();
571}
572
573unsigned int ok_release_with_unknown_source(ArrayOwner *owner) {
574 OSArray *arr = owner->getArraySourceUnknown(); // +0
575 arr->retain(); // +1
576 arr->release(); // +0
577 return arr->getCount();
578}
Artem Dergachev46f34622018-12-15 02:13:26 +0000579
580OSObject *getObject();
581typedef bool (^Blk)(OSObject *);
582
583void test_escape_to_unknown_block(Blk blk) {
584 blk(getObject()); // no-crash
585}
George Karpenkov2c2d0b62019-01-18 19:24:55 +0000586
587using OSObjectPtr = os::smart_ptr<OSObject>;
588
589void test_smart_ptr_uaf() {
590 OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
591 {
592 OSObjectPtr p(obj); // expected-note{{Calling constructor for 'smart_ptr<OSObject>'}}
593 // expected-note@-1{{Returning from constructor for 'smart_ptr<OSObject>'}}
594 // expected-note@os_smart_ptr.h:13{{Taking true branch}}
595 // expected-note@os_smart_ptr.h:14{{Calling 'smart_ptr::_retain'}}
George Karpenkov0f3bbba2019-01-29 19:29:07 +0000596 // expected-note@os_smart_ptr.h:71{{Reference count incremented. The object now has a +2 retain count}}
George Karpenkov2c2d0b62019-01-18 19:24:55 +0000597 // expected-note@os_smart_ptr.h:14{{Returning from 'smart_ptr::_retain'}}
598 } // expected-note{{Calling '~smart_ptr'}}
599 // expected-note@os_smart_ptr.h:35{{Taking true branch}}
600 // expected-note@os_smart_ptr.h:36{{Calling 'smart_ptr::_release'}}
George Karpenkov0f3bbba2019-01-29 19:29:07 +0000601 // expected-note@os_smart_ptr.h:76{{Reference count decremented. The object now has a +1 retain count}}
George Karpenkov2c2d0b62019-01-18 19:24:55 +0000602 // expected-note@os_smart_ptr.h:36{{Returning from 'smart_ptr::_release'}}
603 // expected-note@-5{{Returning from '~smart_ptr'}}
604 obj->release(); // expected-note{{Object released}}
605 obj->release(); // expected-warning{{Reference-counted object is used after it is released}}
606// expected-note@-1{{Reference-counted object is used after it is released}}
607}
608
609void test_smart_ptr_leak() {
610 OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
611 {
612 OSObjectPtr p(obj); // expected-note{{Calling constructor for 'smart_ptr<OSObject>'}}
613 // expected-note@-1{{Returning from constructor for 'smart_ptr<OSObject>'}}
614 // expected-note@os_smart_ptr.h:13{{Taking true branch}}
615 // expected-note@os_smart_ptr.h:14{{Calling 'smart_ptr::_retain'}}
George Karpenkov0f3bbba2019-01-29 19:29:07 +0000616 // expected-note@os_smart_ptr.h:71{{Reference count incremented. The object now has a +2 retain count}}
George Karpenkov2c2d0b62019-01-18 19:24:55 +0000617 // expected-note@os_smart_ptr.h:14{{Returning from 'smart_ptr::_retain'}}
618 } // expected-note{{Calling '~smart_ptr'}}
619 // expected-note@os_smart_ptr.h:35{{Taking true branch}}
620 // expected-note@os_smart_ptr.h:36{{Calling 'smart_ptr::_release'}}
George Karpenkov0f3bbba2019-01-29 19:29:07 +0000621 // expected-note@os_smart_ptr.h:76{{Reference count decremented. The object now has a +1 retain count}}
George Karpenkov2c2d0b62019-01-18 19:24:55 +0000622 // expected-note@os_smart_ptr.h:36{{Returning from 'smart_ptr::_release'}}
623 // expected-note@-5{{Returning from '~smart_ptr'}}
624} // expected-warning{{Potential leak of an object stored into 'obj'}}
625// 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}}
626
627void test_smart_ptr_no_leak() {
628 OSObject *obj = new OSObject;
629 {
630 OSObjectPtr p(obj);
631 }
632 obj->release();
633}
634
635void test_ostypealloc_correct_diagnostic_name() {
636 OSArray *arr = OSTypeAlloc(OSArray); // expected-note{{Call to method 'OSMetaClass::alloc' returns an OSObject of type 'OSArray' with a +1 retain count}}
637 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
638 arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}}
639} // 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}}
640 // expected-warning@-1{{Potential leak of an object stored into 'arr'}}
641
642void escape_elsewhere(OSObject *obj);
643
644void test_free_on_escaped_object_diagnostics() {
645 OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
646 escape_elsewhere(obj); // expected-note{{Object is now not exclusively owned}}
647 obj->free(); // expected-note{{'free' called on an object that may be referenced elsewhere}}
648 // expected-warning@-1{{'free' called on an object that may be referenced elsewhere}}
649}
650
George Karpenkov0f3bbba2019-01-29 19:29:07 +0000651void test_tagged_retain_no_leak() {
652 OSObject *obj = new OSObject;
653 obj->taggedRelease();
654}
655
656void test_tagged_retain_no_uaf() {
657 OSObject *obj = new OSObject;
658 obj->taggedRetain();
659 obj->release();
660 obj->release();
661}
662