blob: 9bc2e20454505823809375e01d7d03d7f6235f99 [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 Karpenkov41dc8de2018-10-11 22:59:16 +000057
George Karpenkov041c9fa2018-12-08 01:18:40 +000058void escape(void *);
George Karpenkov255b0582018-12-21 19:13:40 +000059void escape_with_source(void *p) {}
George Karpenkovff014862018-12-11 01:13:40 +000060bool coin();
61
George Karpenkov5be959c2019-01-11 23:35:17 +000062typedef int kern_return_t;
63typedef kern_return_t IOReturn;
64typedef kern_return_t OSReturn;
65#define kOSReturnSuccess 0
66#define kIOReturnSuccess 0
67
68bool write_into_out_param_on_success(OS_RETURNS_RETAINED OSObject **obj);
69
70void use_out_param() {
71 OSObject *obj;
72 if (write_into_out_param_on_success(&obj)) {
73 obj->release();
74 }
75}
76
77void use_out_param_leak() {
78 OSObject *obj;
79 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){{$}}}}
80} // expected-warning{{Potential leak of an object stored into 'obj'}}
81 // 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}}
82
83bool write_into_out_param_on_failure(OS_RETURNS_RETAINED_ON_ZERO OSObject **obj);
84
85void use_out_param_leak2() {
86 OSObject *obj;
87 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){{$}}}}
88} // expected-warning{{Potential leak of an object stored into 'obj'}}
89 // 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}}
90
91void use_out_param_on_failure() {
92 OSObject *obj;
93 if (!write_into_out_param_on_failure(&obj)) {
94 obj->release();
95 }
96}
97
98IOReturn write_into_out_param_on_nonzero(OS_RETURNS_RETAINED_ON_NONZERO OSObject **obj);
99
100void use_out_param_on_nonzero() {
101 OSObject *obj;
102 if (write_into_out_param_on_nonzero(&obj) != kIOReturnSuccess) {
103 obj->release();
104 }
105}
106
107bool write_into_two_out_params(OS_RETURNS_RETAINED OSObject **a,
108 OS_RETURNS_RETAINED OSObject **b);
109
110void use_write_into_two_out_params() {
111 OSObject *obj1;
112 OSObject *obj2;
113 if (write_into_two_out_params(&obj1, &obj2)) {
114 obj1->release();
115 obj2->release();
116 }
117}
118
119void use_write_two_out_params_leak() {
120 OSObject *obj1;
121 OSObject *obj2;
122 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){{$}}}}
123 // 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){{$}}}}
124} // expected-warning{{Potential leak of an object stored into 'obj1'}}
125 // expected-warning@-1{{Potential leak of an object stored into 'obj2'}}
126 // 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}}
127 // 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}}
128
129void always_write_into_two_out_params(OS_RETURNS_RETAINED OSObject **a,
130 OS_RETURNS_RETAINED OSObject **b);
131
132void use_always_write_into_two_out_params() {
133 OSObject *obj1;
134 OSObject *obj2;
135 always_write_into_two_out_params(&obj1, &obj2);
136 obj1->release();
137 obj2->release();
138}
139
140void use_always_write_into_two_out_params_leak() {
141 OSObject *obj1;
142 OSObject *obj2;
143 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'{{$}}}}
144 // 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'{{$}}}}
145} // expected-warning{{Potential leak of an object stored into 'obj1'}}
146 // expected-warning@-1{{Potential leak of an object stored into 'obj2'}}
147 // 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}}
148 // 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}}
149
150char *write_into_out_param_on_nonnull(OS_RETURNS_RETAINED OSObject **obj);
151
152void use_out_param_osreturn_on_nonnull() {
153 OSObject *obj;
154 if (write_into_out_param_on_nonnull(&obj)) {
155 obj->release();
156 }
157}
158
159void use_out_param_leak_osreturn_on_nonnull() {
160 OSObject *obj;
161 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){{$}}}}
162} // expected-warning{{Potential leak of an object stored into 'obj'}}
163 // 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}}
164
165bool write_optional_out_param(OS_RETURNS_RETAINED OSObject **obj=nullptr);
166
167void use_optional_out_param() {
168 if (write_optional_out_param()) {};
169}
170
171OSReturn write_into_out_param_on_os_success(OS_RETURNS_RETAINED OSObject **obj);
172
173void write_into_non_retained_out_param(OS_RETURNS_NOT_RETAINED OSObject **obj);
174
175void use_write_into_non_retained_out_param() {
176 OSObject *obj;
177 write_into_non_retained_out_param(&obj);
178}
179
180void use_write_into_non_retained_out_param_uaf() {
181 OSObject *obj;
182 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'{{$}}}}
183 obj->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
184 // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
185}
186
187void always_write_into_out_param(OS_RETURNS_RETAINED OSObject **obj);
188
189void pass_through_out_param(OSObject **obj) {
190 always_write_into_out_param(obj);
191}
192
193void always_write_into_out_param_has_source(OS_RETURNS_RETAINED OSObject **obj) {
194 *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
195}
196
197void use_always_write_into_out_param_has_source_leak() {
198 OSObject *obj;
199 always_write_into_out_param_has_source(&obj); // expected-note{{Calling 'always_write_into_out_param_has_source'}}
200 // expected-note@-1{{Returning from 'always_write_into_out_param_has_source'}}
201} // expected-warning{{Potential leak of an object stored into 'obj'}}
202 // 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}}
203
204void use_void_out_param_osreturn() {
205 OSObject *obj;
206 always_write_into_out_param(&obj);
207 obj->release();
208}
209
210void use_void_out_param_osreturn_leak() {
211 OSObject *obj;
212 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'{{$}}}}
213} // expected-warning{{Potential leak of an object stored into 'obj'}}
214 // 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}}
215
216void use_out_param_osreturn() {
217 OSObject *obj;
218 if (write_into_out_param_on_os_success(&obj) == kOSReturnSuccess) {
219 obj->release();
220 }
221}
222
223void use_out_param_leak_osreturn() {
224 OSObject *obj;
225 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){{$}}}}
226} // expected-warning{{Potential leak of an object stored into 'obj'}}
227 // 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}}
228
George Karpenkov03391512019-01-16 23:21:38 +0000229void cleanup(OSObject **obj);
230
231void test_cleanup_escaping() {
232 __attribute__((cleanup(cleanup))) OSObject *obj;
233 always_write_into_out_param(&obj); // no-warning, the value has escaped.
234}
235
George Karpenkov5be959c2019-01-11 23:35:17 +0000236struct StructWithField {
237 OSObject *obj;
238
239 void initViaOutParamCall() { // no warning on writing into fields
240 always_write_into_out_param(&obj);
241 }
242
243};
244
George Karpenkovf5085322018-12-21 02:16:23 +0000245bool os_consume_violation_two_args(OS_CONSUME OSObject *obj, bool extra) {
246 if (coin()) { // expected-note{{Assuming the condition is false}}
247 // expected-note@-1{{Taking false branch}}
248 escape(obj);
249 return true;
250 }
George Karpenkov79f03402018-12-21 19:13:28 +0000251 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 +0000252}
253
George Karpenkovff014862018-12-11 01:13:40 +0000254bool os_consume_violation(OS_CONSUME OSObject *obj) {
255 if (coin()) { // expected-note{{Assuming the condition is false}}
256 // expected-note@-1{{Taking false branch}}
257 escape(obj);
258 return true;
259 }
George Karpenkov79f03402018-12-21 19:13:28 +0000260 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 +0000261}
262
263void os_consume_ok(OS_CONSUME OSObject *obj) {
264 escape(obj);
265}
266
267void use_os_consume_violation() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000268 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 +0000269 os_consume_violation(obj); // expected-note{{Calling 'os_consume_violation'}}
270 // expected-note@-1{{Returning from 'os_consume_violation'}}
271} // 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}}
272 // expected-warning@-1{{Potential leak of an object stored into 'obj'}}
273
George Karpenkovf5085322018-12-21 02:16:23 +0000274void use_os_consume_violation_two_args() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000275 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 +0000276 os_consume_violation_two_args(obj, coin()); // expected-note{{Calling 'os_consume_violation_two_args'}}
277 // expected-note@-1{{Returning from 'os_consume_violation_two_args'}}
278} // 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}}
279 // expected-warning@-1{{Potential leak of an object stored into 'obj'}}
280
George Karpenkovff014862018-12-11 01:13:40 +0000281void use_os_consume_ok() {
282 OSObject *obj = new OSObject;
283 os_consume_ok(obj);
284}
George Karpenkov041c9fa2018-12-08 01:18:40 +0000285
286void test_escaping_into_voidstar() {
287 OSObject *obj = new OSObject;
288 escape(obj);
289}
290
George Karpenkov255b0582018-12-21 19:13:40 +0000291void test_escape_has_source() {
292 OSObject *obj = new OSObject;
293 if (obj)
George Karpenkovd76cc592018-12-21 19:40:44 +0000294 escape_with_source(obj);
George Karpenkov255b0582018-12-21 19:13:40 +0000295 return;
296}
297
George Karpenkova71ec6c2018-12-06 22:06:44 +0000298void test_no_infinite_check_recursion(MyArray *arr) {
299 OSObject *input = new OSObject;
300 OSObject *o = arr->generateObject(input);
301 o->release();
302 input->release();
303}
304
305
George Karpenkova717bc72018-12-05 18:34:54 +0000306void check_param_attribute_propagation(MyArray *parent) {
307 OSArray *arr = new OSArray;
308 parent->consumeReference(arr);
309}
310
311unsigned int check_attribute_propagation(OSArray *arr) {
312 OSObject *other = arr->identity();
313 OSArray *casted = OSDynamicCast(OSArray, other);
314 if (casted)
315 return casted->getCount();
316 return 0;
317}
318
319unsigned int check_attribute_indirect_propagation(MyArray *arr) {
320 OSObject *other = arr->identity();
321 OSArray *casted = OSDynamicCast(OSArray, other);
322 if (casted)
323 return casted->getCount();
324 return 0;
325}
326
George Karpenkovb0b61952018-12-06 22:07:12 +0000327void check_consumes_this(OSArray *owner) {
328 OSArray *arr = new OSArray;
329 arr->putIntoArray(owner);
330}
331
332void check_consumes_this_with_template(OSArray *owner) {
333 OSArray *arr = new OSArray;
334 arr->putIntoT(owner);
335}
336
George Karpenkovbe3f4bd2018-11-30 20:43:42 +0000337void check_free_no_error() {
338 OSArray *arr = OSArray::withCapacity(10);
339 arr->retain();
340 arr->retain();
341 arr->retain();
342 arr->free();
343}
344
345void check_free_use_after_free() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000346 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 +0000347 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
348 arr->free(); // expected-note{{Object released}}
349 arr->retain(); // expected-warning{{Reference-counted object is used after it is released}}
350 // expected-note@-1{{Reference-counted object is used after it is released}}
351}
352
353unsigned int check_leak_explicit_new() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000354 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 +0000355 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}}
356 // expected-warning@-1{{Potential leak of an object stored into 'arr'}}
George Karpenkovbe3f4bd2018-11-30 20:43:42 +0000357}
358
359unsigned int check_leak_factory() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000360 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 +0000361 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}}
362 // expected-warning@-1{{Potential leak of an object stored into 'arr'}}
363}
364
George Karpenkov3bdbeb12018-11-30 02:18:10 +0000365void check_get_object() {
366 OSObject::getObject();
367}
368
369void check_Get_object() {
370 OSObject::GetObject();
371}
372
George Karpenkov83fb5362018-10-31 17:38:46 +0000373void check_custom_iterator_rule(OSArray *arr) {
374 OSIterator *it = arr->getIterator();
375 it->release();
376}
377
George Karpenkove2f09542018-11-30 02:17:57 +0000378void check_iterator_leak(OSArray *arr) {
George Karpenkov4f64b382019-01-10 18:15:57 +0000379 arr->getIterator(); // expected-note{{Call to method 'OSArray::getIterator' returns an OSObject of type 'OSIterator' with a +1 retain count}}
380} // expected-note{{Object leaked: allocated object of type 'OSIterator' is not referenced later}}
381 // expected-warning@-1{{Potential leak of an object of type 'OSIterator}}'
George Karpenkove2f09542018-11-30 02:17:57 +0000382
George Karpenkov081c4772018-10-23 23:11:50 +0000383void check_no_invalidation() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000384 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 +0000385 OtherStruct::doNothingToArray(arr);
386} // expected-warning{{Potential leak of an object stored into 'arr'}}
387 // expected-note@-1{{Object leaked}}
388
George Karpenkov3cfa04e2018-10-25 23:38:41 +0000389void check_no_invalidation_other_struct() {
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 Karpenkov3cfa04e2018-10-25 23:38:41 +0000391 OtherStruct other(arr); // expected-warning{{Potential leak}}
392 // expected-note@-1{{Object leaked}}
393}
394
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000395struct ArrayOwner : public OSObject {
396 OSArray *arr;
397 ArrayOwner(OSArray *arr) : arr(arr) {}
398
399 static ArrayOwner* create(OSArray *arr) {
400 return new ArrayOwner(arr);
401 }
402
403 OSArray *getArray() {
404 return arr;
405 }
406
407 OSArray *createArray() {
408 return OSArray::withCapacity(10);
409 }
410
411 OSArray *createArraySourceUnknown();
412
413 OSArray *getArraySourceUnknown();
414};
415
George Karpenkova1c3bb82018-11-30 02:17:31 +0000416OSArray *generateArray() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000417 return OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}
418 // 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 +0000419}
420
421unsigned int check_leak_good_error_message() {
422 unsigned int out;
423 {
424 OSArray *leaked = generateArray(); // expected-note{{Calling 'generateArray'}}
425 // expected-note@-1{{Returning from 'generateArray'}}
426 out = leaked->getCount(); // expected-warning{{Potential leak of an object stored into 'leaked'}}
427 // 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}}
428 }
429 return out;
430}
431
432unsigned int check_leak_msg_temporary() {
George Karpenkovf893ea12018-11-30 02:17:44 +0000433 return generateArray()->getCount(); // expected-warning{{Potential leak of an object}}
434 // expected-note@-1{{Calling 'generateArray'}}
435 // expected-note@-2{{Returning from 'generateArray'}}
George Karpenkov4f64b382019-01-10 18:15:57 +0000436 // 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 +0000437}
438
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000439void check_confusing_getters() {
440 OSArray *arr = OSArray::withCapacity(10);
441
442 ArrayOwner *AO = ArrayOwner::create(arr);
443 AO->getArray();
444
445 AO->release();
446 arr->release();
447}
448
George Karpenkov081c4772018-10-23 23:11:50 +0000449void check_rc_consumed() {
450 OSArray *arr = OSArray::withCapacity(10);
451 OSArray::consumeArray(arr);
452}
453
454void check_rc_consume_temporary() {
455 OSArray::consumeArray(OSArray::withCapacity(10));
456}
457
458void check_rc_getter() {
459 OSArray *arr = OSArray::MaskedGetter();
460 (void)arr;
461}
462
463void check_rc_create() {
464 OSArray *arr = OSArray::getOoopsActuallyCreate();
465 arr->release();
466}
467
468
George Karpenkov41dc8de2018-10-11 22:59:16 +0000469void check_dynamic_cast() {
470 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1));
471 arr->release();
472}
473
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000474unsigned int check_dynamic_cast_no_null_on_orig(OSObject *obj) {
475 OSArray *arr = OSDynamicCast(OSArray, obj);
476 if (arr) {
477 return arr->getCount();
478 } else {
479
480 // The fact that dynamic cast has failed should not imply that
481 // the input object was null.
482 return obj->foo(); // no-warning
483 }
484}
485
486void check_dynamic_cast_null_branch(OSObject *obj) {
George Karpenkove2f09542018-11-30 02:17:57 +0000487 OSArray *arr1 = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000488 OSArray *arr = OSDynamicCast(OSArray, obj);
489 if (!arr) // expected-note{{Taking true branch}}
George Karpenkova1c3bb82018-11-30 02:17:31 +0000490 return; // expected-warning{{Potential leak of an object stored into 'arr1'}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000491 // expected-note@-1{{Object leaked}}
492 arr1->release();
493}
494
George Karpenkov41dc8de2018-10-11 22:59:16 +0000495void check_dynamic_cast_null_check() {
George Karpenkove2f09542018-11-30 02:17:57 +0000496 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); // expected-note{{Call to method 'OSObject::generateObject' returns an OSObject}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000497 // expected-warning@-1{{Potential leak of an object}}
498 // expected-note@-2{{Object leaked}}
George Karpenkov41dc8de2018-10-11 22:59:16 +0000499 if (!arr)
500 return;
501 arr->release();
502}
503
George Karpenkovab0011e2018-08-23 00:26:59 +0000504void use_after_release() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000505 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 +0000506 arr->release(); // expected-note{{Object released}}
507 arr->getCount(); // expected-warning{{Reference-counted object is used after it is released}}
508 // expected-note@-1{{Reference-counted object is used after it is released}}
509}
510
511void potential_leak() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000512 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 +0000513 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
514 arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}}
515 arr->getCount();
516} // expected-warning{{Potential leak of an object stored into 'arr'}}
517 // 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}}
518
519void proper_cleanup() {
520 OSArray *arr = OSArray::withCapacity(10); // +1
521 arr->retain(); // +2
522 arr->release(); // +1
523 arr->getCount();
524 arr->release(); // 0
525}
526
George Karpenkovab0011e2018-08-23 00:26:59 +0000527unsigned int no_warning_on_getter(ArrayOwner *owner) {
528 OSArray *arr = owner->getArray();
529 return arr->getCount();
530}
531
532unsigned int warn_on_overrelease(ArrayOwner *owner) {
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000533 // FIXME: summaries are not applied in case the source of the getter/setter
534 // is known.
535 // rdar://45681203
536 OSArray *arr = owner->getArray();
537 arr->release();
George Karpenkovab0011e2018-08-23 00:26:59 +0000538 return arr->getCount();
539}
540
541unsigned int nowarn_on_release_of_created(ArrayOwner *owner) {
542 OSArray *arr = owner->createArray();
543 unsigned int out = arr->getCount();
544 arr->release();
545 return out;
546}
547
548unsigned int nowarn_on_release_of_created_source_unknown(ArrayOwner *owner) {
549 OSArray *arr = owner->createArraySourceUnknown();
550 unsigned int out = arr->getCount();
551 arr->release();
552 return out;
553}
554
555unsigned int no_warn_ok_release(ArrayOwner *owner) {
556 OSArray *arr = owner->getArray(); // +0
557 arr->retain(); // +1
558 arr->release(); // +0
559 return arr->getCount(); // no-warning
560}
561
562unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) {
George Karpenkov4f64b382019-01-10 18:15:57 +0000563 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 +0000564 arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
565 // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
566 return arr->getCount();
567}
568
569unsigned int ok_release_with_unknown_source(ArrayOwner *owner) {
570 OSArray *arr = owner->getArraySourceUnknown(); // +0
571 arr->retain(); // +1
572 arr->release(); // +0
573 return arr->getCount();
574}
Artem Dergachev46f34622018-12-15 02:13:26 +0000575
576OSObject *getObject();
577typedef bool (^Blk)(OSObject *);
578
579void test_escape_to_unknown_block(Blk blk) {
580 blk(getObject()); // no-crash
581}
George Karpenkov2c2d0b62019-01-18 19:24:55 +0000582
583using OSObjectPtr = os::smart_ptr<OSObject>;
584
585void test_smart_ptr_uaf() {
586 OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
587 {
588 OSObjectPtr p(obj); // expected-note{{Calling constructor for 'smart_ptr<OSObject>'}}
589 // expected-note@-1{{Returning from constructor for 'smart_ptr<OSObject>'}}
590 // expected-note@os_smart_ptr.h:13{{Taking true branch}}
591 // expected-note@os_smart_ptr.h:14{{Calling 'smart_ptr::_retain'}}
592 // expected-note@os_smart_ptr.h:72{{Reference count incremented. The object now has a +2 retain count}}
593 // expected-note@os_smart_ptr.h:14{{Returning from 'smart_ptr::_retain'}}
594 } // expected-note{{Calling '~smart_ptr'}}
595 // expected-note@os_smart_ptr.h:35{{Taking true branch}}
596 // expected-note@os_smart_ptr.h:36{{Calling 'smart_ptr::_release'}}
597 // expected-note@os_smart_ptr.h:77{{Reference count decremented. The object now has a +1 retain count}}
598 // expected-note@os_smart_ptr.h:36{{Returning from 'smart_ptr::_release'}}
599 // expected-note@-5{{Returning from '~smart_ptr'}}
600 obj->release(); // expected-note{{Object released}}
601 obj->release(); // expected-warning{{Reference-counted object is used after it is released}}
602// expected-note@-1{{Reference-counted object is used after it is released}}
603}
604
605void test_smart_ptr_leak() {
606 OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
607 {
608 OSObjectPtr p(obj); // expected-note{{Calling constructor for 'smart_ptr<OSObject>'}}
609 // expected-note@-1{{Returning from constructor for 'smart_ptr<OSObject>'}}
610 // expected-note@os_smart_ptr.h:13{{Taking true branch}}
611 // expected-note@os_smart_ptr.h:14{{Calling 'smart_ptr::_retain'}}
612 // expected-note@os_smart_ptr.h:72{{Reference count incremented. The object now has a +2 retain count}}
613 // expected-note@os_smart_ptr.h:14{{Returning from 'smart_ptr::_retain'}}
614 } // expected-note{{Calling '~smart_ptr'}}
615 // expected-note@os_smart_ptr.h:35{{Taking true branch}}
616 // expected-note@os_smart_ptr.h:36{{Calling 'smart_ptr::_release'}}
617 // expected-note@os_smart_ptr.h:77{{Reference count decremented. The object now has a +1 retain count}}
618 // expected-note@os_smart_ptr.h:36{{Returning from 'smart_ptr::_release'}}
619 // expected-note@-5{{Returning from '~smart_ptr'}}
620} // expected-warning{{Potential leak of an object stored into 'obj'}}
621// 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}}
622
623void test_smart_ptr_no_leak() {
624 OSObject *obj = new OSObject;
625 {
626 OSObjectPtr p(obj);
627 }
628 obj->release();
629}
630
631void test_ostypealloc_correct_diagnostic_name() {
632 OSArray *arr = OSTypeAlloc(OSArray); // expected-note{{Call to method 'OSMetaClass::alloc' returns an OSObject of type 'OSArray' with a +1 retain count}}
633 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
634 arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}}
635} // 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}}
636 // expected-warning@-1{{Potential leak of an object stored into 'arr'}}
637
638void escape_elsewhere(OSObject *obj);
639
640void test_free_on_escaped_object_diagnostics() {
641 OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
642 escape_elsewhere(obj); // expected-note{{Object is now not exclusively owned}}
643 obj->free(); // expected-note{{'free' called on an object that may be referenced elsewhere}}
644 // expected-warning@-1{{'free' called on an object that may be referenced elsewhere}}
645}
646