blob: d88349dcd807ed87d6141b7dbf56d583e692f847 [file] [log] [blame]
Artem Dergachevb0914e72019-10-19 00:08:17 +00001// RUN: %clang_analyze_cc1 -std=c++14 -fblocks -analyze -analyzer-output=text\
Artem Dergachevb03854f2019-06-19 23:33:34 +00002// RUN: -analyzer-checker=core,osx,debug.ExprInspection -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
Artem Dergachevb03854f2019-06-19 23:33:34 +00007void clang_analyzer_eval(bool);
8
George Karpenkov83fb5362018-10-31 17:38:46 +00009struct OSIterator : public OSObject {
George Karpenkova1c3bb82018-11-30 02:17:31 +000010 static const OSMetaClass * const metaClass;
George Karpenkov83fb5362018-10-31 17:38:46 +000011};
12
George Karpenkovab0011e2018-08-23 00:26:59 +000013struct OSArray : public OSObject {
14 unsigned int getCount();
15
George Karpenkova717bc72018-12-05 18:34:54 +000016 OSIterator * getIterator();
17
18 OSObject *identity() override;
19
George Karpenkova71ec6c2018-12-06 22:06:44 +000020 virtual OSObject *generateObject(OSObject *input);
21
George Karpenkova717bc72018-12-05 18:34:54 +000022 virtual void consumeReference(OS_CONSUME OSArray *other);
23
George Karpenkovb0b61952018-12-06 22:07:12 +000024 void putIntoArray(OSArray *array) OS_CONSUMES_THIS;
25
26 template <typename T>
27 void putIntoT(T *owner) OS_CONSUMES_THIS;
28
George Karpenkov62db8862018-11-30 02:18:23 +000029 static OSArray *generateArrayHasCode() {
30 return new OSArray;
31 }
32
George Karpenkovab0011e2018-08-23 00:26:59 +000033 static OSArray *withCapacity(unsigned int capacity);
George Karpenkov081c4772018-10-23 23:11:50 +000034 static void consumeArray(OS_CONSUME OSArray * array);
35
George Karpenkovd37ff4e2019-01-29 19:29:59 +000036 static OSArray* consumeArrayHasCode(OS_CONSUME OSArray * array) { // expected-note{{Parameter 'array' starts at +1, as it is marked as consuming}}
37 return nullptr; // expected-warning{{Potential leak of an object of type 'OSArray'}}
38// expected-note@-1{{Object leaked: allocated object of type 'OSArray' is not referenced later in this execution path and has a retain count of +1}}
George Karpenkov081c4772018-10-23 23:11:50 +000039 }
40
George Karpenkovd37ff4e2019-01-29 19:29:59 +000041
George Karpenkov081c4772018-10-23 23:11:50 +000042 static OS_RETURNS_NOT_RETAINED OSArray *MaskedGetter();
43 static OS_RETURNS_RETAINED OSArray *getOoopsActuallyCreate();
44
George Karpenkov41dc8de2018-10-11 22:59:16 +000045 static const OSMetaClass * const metaClass;
George Karpenkovab0011e2018-08-23 00:26:59 +000046};
47
George Karpenkova717bc72018-12-05 18:34:54 +000048struct MyArray : public OSArray {
49 void consumeReference(OSArray *other) override;
50
51 OSObject *identity() override;
George Karpenkova71ec6c2018-12-06 22:06:44 +000052
53 OSObject *generateObject(OSObject *input) override;
George Karpenkova717bc72018-12-05 18:34:54 +000054};
55
Artem Dergachev3500cc82020-04-01 18:15:00 +030056// These are never refcounted.
57struct OSSymbol : OSObject {};
58
George Karpenkov081c4772018-10-23 23:11:50 +000059struct OtherStruct {
60 static void doNothingToArray(OSArray *array);
George Karpenkov3cfa04e2018-10-25 23:38:41 +000061 OtherStruct(OSArray *arr);
George Karpenkov081c4772018-10-23 23:11:50 +000062};
63
George Karpenkovdb0c66e2019-01-22 19:50:47 +000064bool test_meta_cast_no_leak(OSMetaClassBase *arg) {
65 return arg && arg->metaCast("blah") != nullptr;
66}
George Karpenkov41dc8de2018-10-11 22:59:16 +000067
George Karpenkovd37ff4e2019-01-29 19:29:59 +000068static void consumedMismatch(OS_CONSUME OSObject *a,
69 OSObject *b) { // expected-note{{Parameter 'b' starts at +0}}
70 a->release();
71 b->retain(); // expected-note{{Reference count incremented. The object now has a +1 retain count}}
72} // expected-warning{{Potential leak of an object of type 'OSObject'}}
73// expected-note@-1{{Object leaked: allocated object of type 'OSObject' is not referenced later in this execution path and has a retain count of +1}}
74
George Karpenkov041c9fa2018-12-08 01:18:40 +000075void escape(void *);
George Karpenkov255b0582018-12-21 19:13:40 +000076void escape_with_source(void *p) {}
George Karpenkovff014862018-12-11 01:13:40 +000077bool coin();
78
George Karpenkov5be959c2019-01-11 23:35:17 +000079typedef int kern_return_t;
80typedef kern_return_t IOReturn;
81typedef kern_return_t OSReturn;
82#define kOSReturnSuccess 0
83#define kIOReturnSuccess 0
84
85bool write_into_out_param_on_success(OS_RETURNS_RETAINED OSObject **obj);
86
87void use_out_param() {
88 OSObject *obj;
89 if (write_into_out_param_on_success(&obj)) {
90 obj->release();
91 }
92}
93
94void use_out_param_leak() {
95 OSObject *obj;
96 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){{$}}}}
97} // expected-warning{{Potential leak of an object stored into 'obj'}}
98 // 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}}
99
100bool write_into_out_param_on_failure(OS_RETURNS_RETAINED_ON_ZERO OSObject **obj);
101
102void use_out_param_leak2() {
103 OSObject *obj;
104 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){{$}}}}
105} // expected-warning{{Potential leak of an object stored into 'obj'}}
106 // 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}}
107
108void use_out_param_on_failure() {
109 OSObject *obj;
110 if (!write_into_out_param_on_failure(&obj)) {
111 obj->release();
112 }
113}
114
115IOReturn write_into_out_param_on_nonzero(OS_RETURNS_RETAINED_ON_NONZERO OSObject **obj);
116
117void use_out_param_on_nonzero() {
118 OSObject *obj;
119 if (write_into_out_param_on_nonzero(&obj) != kIOReturnSuccess) {
120 obj->release();
121 }
122}
123
124bool write_into_two_out_params(OS_RETURNS_RETAINED OSObject **a,
125 OS_RETURNS_RETAINED OSObject **b);
126
127void use_write_into_two_out_params() {
128 OSObject *obj1;
129 OSObject *obj2;
130 if (write_into_two_out_params(&obj1, &obj2)) {
131 obj1->release();
132 obj2->release();
133 }
134}
135
136void use_write_two_out_params_leak() {
137 OSObject *obj1;
138 OSObject *obj2;
139 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){{$}}}}
140 // 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){{$}}}}
141} // expected-warning{{Potential leak of an object stored into 'obj1'}}
142 // expected-warning@-1{{Potential leak of an object stored into 'obj2'}}
143 // 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}}
144 // 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}}
145
146void always_write_into_two_out_params(OS_RETURNS_RETAINED OSObject **a,
147 OS_RETURNS_RETAINED OSObject **b);
148
149void use_always_write_into_two_out_params() {
150 OSObject *obj1;
151 OSObject *obj2;
152 always_write_into_two_out_params(&obj1, &obj2);
153 obj1->release();
154 obj2->release();
155}
156
157void use_always_write_into_two_out_params_leak() {
158 OSObject *obj1;
159 OSObject *obj2;
160 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'{{$}}}}
161 // 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'{{$}}}}
162} // expected-warning{{Potential leak of an object stored into 'obj1'}}
163 // expected-warning@-1{{Potential leak of an object stored into 'obj2'}}
164 // 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}}
165 // 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}}
166
167char *write_into_out_param_on_nonnull(OS_RETURNS_RETAINED OSObject **obj);
168
169void use_out_param_osreturn_on_nonnull() {
170 OSObject *obj;
171 if (write_into_out_param_on_nonnull(&obj)) {
172 obj->release();
173 }
174}
175
176void use_out_param_leak_osreturn_on_nonnull() {
177 OSObject *obj;
178 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){{$}}}}
179} // expected-warning{{Potential leak of an object stored into 'obj'}}
180 // 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}}
181
182bool write_optional_out_param(OS_RETURNS_RETAINED OSObject **obj=nullptr);
183
184void use_optional_out_param() {
185 if (write_optional_out_param()) {};
186}
187
188OSReturn write_into_out_param_on_os_success(OS_RETURNS_RETAINED OSObject **obj);
189
190void write_into_non_retained_out_param(OS_RETURNS_NOT_RETAINED OSObject **obj);
191
192void use_write_into_non_retained_out_param() {
193 OSObject *obj;
194 write_into_non_retained_out_param(&obj);
195}
196
197void use_write_into_non_retained_out_param_uaf() {
198 OSObject *obj;
199 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'{{$}}}}
200 obj->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
201 // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
202}
203
204void always_write_into_out_param(OS_RETURNS_RETAINED OSObject **obj);
205
206void pass_through_out_param(OSObject **obj) {
207 always_write_into_out_param(obj);
208}
209
210void always_write_into_out_param_has_source(OS_RETURNS_RETAINED OSObject **obj) {
211 *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
212}
213
214void use_always_write_into_out_param_has_source_leak() {
215 OSObject *obj;
216 always_write_into_out_param_has_source(&obj); // expected-note{{Calling 'always_write_into_out_param_has_source'}}
217 // expected-note@-1{{Returning from 'always_write_into_out_param_has_source'}}
218} // expected-warning{{Potential leak of an object stored into 'obj'}}
219 // 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}}
220
221void use_void_out_param_osreturn() {
222 OSObject *obj;
223 always_write_into_out_param(&obj);
224 obj->release();
225}
226
227void use_void_out_param_osreturn_leak() {
228 OSObject *obj;
229 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'{{$}}}}
230} // expected-warning{{Potential leak of an object stored into 'obj'}}
231 // 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}}
232
233void use_out_param_osreturn() {
234 OSObject *obj;
235 if (write_into_out_param_on_os_success(&obj) == kOSReturnSuccess) {
236 obj->release();
237 }
238}
239
240void use_out_param_leak_osreturn() {
241 OSObject *obj;
242 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){{$}}}}
243} // expected-warning{{Potential leak of an object stored into 'obj'}}
244 // 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}}
245
George Karpenkov03391512019-01-16 23:21:38 +0000246void cleanup(OSObject **obj);
247
248void test_cleanup_escaping() {
249 __attribute__((cleanup(cleanup))) OSObject *obj;
250 always_write_into_out_param(&obj); // no-warning, the value has escaped.
251}
252
George Karpenkov5be959c2019-01-11 23:35:17 +0000253struct StructWithField {
254 OSObject *obj;
255
256 void initViaOutParamCall() { // no warning on writing into fields
257 always_write_into_out_param(&obj);
258 }
259
260};
261
George Karpenkovf5085322018-12-21 02:16:23 +0000262bool os_consume_violation_two_args(OS_CONSUME OSObject *obj, bool extra) {
263 if (coin()) { // expected-note{{Assuming the condition is false}}
264 // expected-note@-1{{Taking false branch}}
265 escape(obj);
266 return true;
267 }
George Karpenkov79f03402018-12-21 19:13:28 +0000268 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 +0000269}
270
George Karpenkovff014862018-12-11 01:13:40 +0000271bool os_consume_violation(OS_CONSUME OSObject *obj) {
272 if (coin()) { // expected-note{{Assuming the condition is false}}
273 // expected-note@-1{{Taking false branch}}
274 escape(obj);
275 return true;
276 }
George Karpenkov79f03402018-12-21 19:13:28 +0000277 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 +0000278}
279
280void os_consume_ok(OS_CONSUME OSObject *obj) {
281 escape(obj);
282}
283
284void use_os_consume_violation() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000285 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 +0000286 os_consume_violation(obj); // expected-note{{Calling 'os_consume_violation'}}
287 // expected-note@-1{{Returning from 'os_consume_violation'}}
288} // 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}}
289 // expected-warning@-1{{Potential leak of an object stored into 'obj'}}
290
George Karpenkovf5085322018-12-21 02:16:23 +0000291void use_os_consume_violation_two_args() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000292 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 +0000293 os_consume_violation_two_args(obj, coin()); // expected-note{{Calling 'os_consume_violation_two_args'}}
294 // expected-note@-1{{Returning from 'os_consume_violation_two_args'}}
295} // 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}}
296 // expected-warning@-1{{Potential leak of an object stored into 'obj'}}
297
George Karpenkovff014862018-12-11 01:13:40 +0000298void use_os_consume_ok() {
299 OSObject *obj = new OSObject;
300 os_consume_ok(obj);
301}
George Karpenkov041c9fa2018-12-08 01:18:40 +0000302
303void test_escaping_into_voidstar() {
304 OSObject *obj = new OSObject;
305 escape(obj);
306}
307
George Karpenkov255b0582018-12-21 19:13:40 +0000308void test_escape_has_source() {
309 OSObject *obj = new OSObject;
310 if (obj)
George Karpenkovd76cc592018-12-21 19:40:44 +0000311 escape_with_source(obj);
George Karpenkov255b0582018-12-21 19:13:40 +0000312 return;
313}
314
George Karpenkova71ec6c2018-12-06 22:06:44 +0000315void test_no_infinite_check_recursion(MyArray *arr) {
316 OSObject *input = new OSObject;
317 OSObject *o = arr->generateObject(input);
318 o->release();
319 input->release();
320}
321
322
George Karpenkova717bc72018-12-05 18:34:54 +0000323void check_param_attribute_propagation(MyArray *parent) {
324 OSArray *arr = new OSArray;
325 parent->consumeReference(arr);
326}
327
328unsigned int check_attribute_propagation(OSArray *arr) {
329 OSObject *other = arr->identity();
330 OSArray *casted = OSDynamicCast(OSArray, other);
331 if (casted)
332 return casted->getCount();
333 return 0;
334}
335
336unsigned int check_attribute_indirect_propagation(MyArray *arr) {
337 OSObject *other = arr->identity();
338 OSArray *casted = OSDynamicCast(OSArray, other);
339 if (casted)
340 return casted->getCount();
341 return 0;
342}
343
George Karpenkovb0b61952018-12-06 22:07:12 +0000344void check_consumes_this(OSArray *owner) {
345 OSArray *arr = new OSArray;
346 arr->putIntoArray(owner);
347}
348
349void check_consumes_this_with_template(OSArray *owner) {
350 OSArray *arr = new OSArray;
351 arr->putIntoT(owner);
352}
353
George Karpenkovbe3f4bd2018-11-30 20:43:42 +0000354void check_free_no_error() {
355 OSArray *arr = OSArray::withCapacity(10);
356 arr->retain();
357 arr->retain();
358 arr->retain();
359 arr->free();
360}
361
362void check_free_use_after_free() {
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 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
365 arr->free(); // expected-note{{Object released}}
366 arr->retain(); // expected-warning{{Reference-counted object is used after it is released}}
367 // expected-note@-1{{Reference-counted object is used after it is released}}
368}
369
370unsigned int check_leak_explicit_new() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000371 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 +0000372 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}}
373 // expected-warning@-1{{Potential leak of an object stored into 'arr'}}
George Karpenkovbe3f4bd2018-11-30 20:43:42 +0000374}
375
376unsigned int check_leak_factory() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000377 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 +0000378 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}}
379 // expected-warning@-1{{Potential leak of an object stored into 'arr'}}
380}
381
George Karpenkov3bdbeb12018-11-30 02:18:10 +0000382void check_get_object() {
383 OSObject::getObject();
384}
385
386void check_Get_object() {
387 OSObject::GetObject();
388}
389
George Karpenkov83fb5362018-10-31 17:38:46 +0000390void check_custom_iterator_rule(OSArray *arr) {
391 OSIterator *it = arr->getIterator();
392 it->release();
393}
394
George Karpenkove2f09542018-11-30 02:17:57 +0000395void check_iterator_leak(OSArray *arr) {
George Karpenkov4f64b382019-01-10 18:15:57 +0000396 arr->getIterator(); // expected-note{{Call to method 'OSArray::getIterator' returns an OSObject of type 'OSIterator' with a +1 retain count}}
397} // expected-note{{Object leaked: allocated object of type 'OSIterator' is not referenced later}}
398 // expected-warning@-1{{Potential leak of an object of type 'OSIterator}}'
George Karpenkove2f09542018-11-30 02:17:57 +0000399
George Karpenkov081c4772018-10-23 23:11:50 +0000400void check_no_invalidation() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000401 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 +0000402 OtherStruct::doNothingToArray(arr);
403} // expected-warning{{Potential leak of an object stored into 'arr'}}
404 // expected-note@-1{{Object leaked}}
405
George Karpenkov3cfa04e2018-10-25 23:38:41 +0000406void check_no_invalidation_other_struct() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000407 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 +0000408 OtherStruct other(arr); // expected-warning{{Potential leak}}
409 // expected-note@-1{{Object leaked}}
410}
411
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000412struct ArrayOwner : public OSObject {
413 OSArray *arr;
414 ArrayOwner(OSArray *arr) : arr(arr) {}
415
416 static ArrayOwner* create(OSArray *arr) {
417 return new ArrayOwner(arr);
418 }
419
420 OSArray *getArray() {
421 return arr;
422 }
423
424 OSArray *createArray() {
425 return OSArray::withCapacity(10);
426 }
427
428 OSArray *createArraySourceUnknown();
429
430 OSArray *getArraySourceUnknown();
431};
432
George Karpenkova1c3bb82018-11-30 02:17:31 +0000433OSArray *generateArray() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000434 return OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}
435 // 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 +0000436}
437
438unsigned int check_leak_good_error_message() {
439 unsigned int out;
440 {
441 OSArray *leaked = generateArray(); // expected-note{{Calling 'generateArray'}}
442 // expected-note@-1{{Returning from 'generateArray'}}
443 out = leaked->getCount(); // expected-warning{{Potential leak of an object stored into 'leaked'}}
444 // 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}}
445 }
446 return out;
447}
448
449unsigned int check_leak_msg_temporary() {
George Karpenkovf893ea12018-11-30 02:17:44 +0000450 return generateArray()->getCount(); // expected-warning{{Potential leak of an object}}
451 // expected-note@-1{{Calling 'generateArray'}}
452 // expected-note@-2{{Returning from 'generateArray'}}
George Karpenkov4f64b382019-01-10 18:15:57 +0000453 // 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 +0000454}
455
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000456void check_confusing_getters() {
457 OSArray *arr = OSArray::withCapacity(10);
458
459 ArrayOwner *AO = ArrayOwner::create(arr);
460 AO->getArray();
461
462 AO->release();
463 arr->release();
464}
465
George Karpenkov081c4772018-10-23 23:11:50 +0000466void check_rc_consumed() {
467 OSArray *arr = OSArray::withCapacity(10);
468 OSArray::consumeArray(arr);
469}
470
471void check_rc_consume_temporary() {
472 OSArray::consumeArray(OSArray::withCapacity(10));
473}
474
475void check_rc_getter() {
476 OSArray *arr = OSArray::MaskedGetter();
477 (void)arr;
478}
479
480void check_rc_create() {
481 OSArray *arr = OSArray::getOoopsActuallyCreate();
482 arr->release();
483}
484
485
George Karpenkov41dc8de2018-10-11 22:59:16 +0000486void check_dynamic_cast() {
487 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1));
488 arr->release();
489}
490
Artem Dergachevb03854f2019-06-19 23:33:34 +0000491void check_required_cast() {
492 OSArray *arr = OSRequiredCast(OSArray, OSObject::generateObject(1));
493 arr->release(); // no-warning
494}
495
496void check_cast_behavior(OSObject *obj) {
497 OSArray *arr1 = OSDynamicCast(OSArray, obj);
498 clang_analyzer_eval(arr1 == obj); // expected-warning{{TRUE}}
499 // expected-note@-1{{TRUE}}
500 // expected-note@-2{{Assuming 'arr1' is not equal to 'obj'}}
501 // expected-warning@-3{{FALSE}}
502 // expected-note@-4 {{FALSE}}
503 OSArray *arr2 = OSRequiredCast(OSArray, obj);
504 clang_analyzer_eval(arr2 == obj); // expected-warning{{TRUE}}
505 // expected-note@-1{{TRUE}}
506}
507
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000508unsigned int check_dynamic_cast_no_null_on_orig(OSObject *obj) {
509 OSArray *arr = OSDynamicCast(OSArray, obj);
510 if (arr) {
511 return arr->getCount();
512 } else {
513
514 // The fact that dynamic cast has failed should not imply that
515 // the input object was null.
516 return obj->foo(); // no-warning
517 }
518}
519
520void check_dynamic_cast_null_branch(OSObject *obj) {
George Karpenkove2f09542018-11-30 02:17:57 +0000521 OSArray *arr1 = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject}}
George Karpenkova9e29562019-01-22 19:51:00 +0000522 OSArray *arr = OSDynamicCast(OSArray, obj); // expected-note{{Assuming dynamic cast returns null due to type mismatch}}
Csaba Dabis4b0184b2019-05-29 20:06:09 +0000523 if (!arr) // expected-note{{'arr' is null}}
524 // expected-note@-1{{Taking true branch}}
George Karpenkova1c3bb82018-11-30 02:17:31 +0000525 return; // expected-warning{{Potential leak of an object stored into 'arr1'}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000526 // expected-note@-1{{Object leaked}}
527 arr1->release();
528}
529
George Karpenkov41dc8de2018-10-11 22:59:16 +0000530void check_dynamic_cast_null_check() {
George Karpenkove2f09542018-11-30 02:17:57 +0000531 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); // expected-note{{Call to method 'OSObject::generateObject' returns an OSObject}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000532 // expected-warning@-1{{Potential leak of an object}}
533 // expected-note@-2{{Object leaked}}
George Karpenkova9e29562019-01-22 19:51:00 +0000534 // expected-note@-3{{Assuming dynamic cast returns null due to type mismatch}}
George Karpenkov41dc8de2018-10-11 22:59:16 +0000535 if (!arr)
536 return;
537 arr->release();
538}
539
George Karpenkovab0011e2018-08-23 00:26:59 +0000540void use_after_release() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000541 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 +0000542 arr->release(); // expected-note{{Object released}}
543 arr->getCount(); // expected-warning{{Reference-counted object is used after it is released}}
544 // expected-note@-1{{Reference-counted object is used after it is released}}
545}
546
547void potential_leak() {
George Karpenkov4f64b382019-01-10 18:15:57 +0000548 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 +0000549 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
550 arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}}
551 arr->getCount();
552} // expected-warning{{Potential leak of an object stored into 'arr'}}
553 // 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}}
554
555void proper_cleanup() {
556 OSArray *arr = OSArray::withCapacity(10); // +1
557 arr->retain(); // +2
558 arr->release(); // +1
559 arr->getCount();
560 arr->release(); // 0
561}
562
George Karpenkovab0011e2018-08-23 00:26:59 +0000563unsigned int no_warning_on_getter(ArrayOwner *owner) {
564 OSArray *arr = owner->getArray();
565 return arr->getCount();
566}
567
568unsigned int warn_on_overrelease(ArrayOwner *owner) {
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000569 // FIXME: summaries are not applied in case the source of the getter/setter
570 // is known.
571 // rdar://45681203
572 OSArray *arr = owner->getArray();
573 arr->release();
George Karpenkovab0011e2018-08-23 00:26:59 +0000574 return arr->getCount();
575}
576
577unsigned int nowarn_on_release_of_created(ArrayOwner *owner) {
578 OSArray *arr = owner->createArray();
579 unsigned int out = arr->getCount();
580 arr->release();
581 return out;
582}
583
584unsigned int nowarn_on_release_of_created_source_unknown(ArrayOwner *owner) {
585 OSArray *arr = owner->createArraySourceUnknown();
586 unsigned int out = arr->getCount();
587 arr->release();
588 return out;
589}
590
591unsigned int no_warn_ok_release(ArrayOwner *owner) {
592 OSArray *arr = owner->getArray(); // +0
593 arr->retain(); // +1
594 arr->release(); // +0
595 return arr->getCount(); // no-warning
596}
597
598unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) {
George Karpenkov4f64b382019-01-10 18:15:57 +0000599 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 +0000600 arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
601 // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
602 return arr->getCount();
603}
604
605unsigned int ok_release_with_unknown_source(ArrayOwner *owner) {
606 OSArray *arr = owner->getArraySourceUnknown(); // +0
607 arr->retain(); // +1
608 arr->release(); // +0
609 return arr->getCount();
610}
Artem Dergachev46f34622018-12-15 02:13:26 +0000611
612OSObject *getObject();
613typedef bool (^Blk)(OSObject *);
614
615void test_escape_to_unknown_block(Blk blk) {
616 blk(getObject()); // no-crash
617}
George Karpenkov2c2d0b62019-01-18 19:24:55 +0000618
619using OSObjectPtr = os::smart_ptr<OSObject>;
620
621void test_smart_ptr_uaf() {
622 OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
623 {
624 OSObjectPtr p(obj); // expected-note{{Calling constructor for 'smart_ptr<OSObject>'}}
625 // expected-note@-1{{Returning from constructor for 'smart_ptr<OSObject>'}}
Csaba Dabisd1f0ec32019-05-29 20:29:02 +0000626 // expected-note@os_smart_ptr.h:13{{Field 'pointer' is non-null}}
George Karpenkov2c2d0b62019-01-18 19:24:55 +0000627 // expected-note@os_smart_ptr.h:13{{Taking true branch}}
628 // expected-note@os_smart_ptr.h:14{{Calling 'smart_ptr::_retain'}}
George Karpenkov0f3bbba2019-01-29 19:29:07 +0000629 // 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 +0000630 // expected-note@os_smart_ptr.h:14{{Returning from 'smart_ptr::_retain'}}
631 } // expected-note{{Calling '~smart_ptr'}}
Csaba Dabisd1f0ec32019-05-29 20:29:02 +0000632 // expected-note@os_smart_ptr.h:35{{Field 'pointer' is non-null}}
George Karpenkov2c2d0b62019-01-18 19:24:55 +0000633 // expected-note@os_smart_ptr.h:35{{Taking true branch}}
634 // expected-note@os_smart_ptr.h:36{{Calling 'smart_ptr::_release'}}
George Karpenkov0f3bbba2019-01-29 19:29:07 +0000635 // 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 +0000636 // expected-note@os_smart_ptr.h:36{{Returning from 'smart_ptr::_release'}}
Csaba Dabisd1f0ec32019-05-29 20:29:02 +0000637 // expected-note@-6{{Returning from '~smart_ptr'}}
George Karpenkov2c2d0b62019-01-18 19:24:55 +0000638 obj->release(); // expected-note{{Object released}}
639 obj->release(); // expected-warning{{Reference-counted object is used after it is released}}
640// expected-note@-1{{Reference-counted object is used after it is released}}
641}
642
643void test_smart_ptr_leak() {
644 OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
645 {
646 OSObjectPtr p(obj); // expected-note{{Calling constructor for 'smart_ptr<OSObject>'}}
647 // expected-note@-1{{Returning from constructor for 'smart_ptr<OSObject>'}}
Csaba Dabisd1f0ec32019-05-29 20:29:02 +0000648 // expected-note@os_smart_ptr.h:13{{Field 'pointer' is non-null}}
George Karpenkov2c2d0b62019-01-18 19:24:55 +0000649 // expected-note@os_smart_ptr.h:13{{Taking true branch}}
650 // expected-note@os_smart_ptr.h:14{{Calling 'smart_ptr::_retain'}}
George Karpenkov0f3bbba2019-01-29 19:29:07 +0000651 // 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 +0000652 // expected-note@os_smart_ptr.h:14{{Returning from 'smart_ptr::_retain'}}
653 } // expected-note{{Calling '~smart_ptr'}}
Csaba Dabisd1f0ec32019-05-29 20:29:02 +0000654 // expected-note@os_smart_ptr.h:35{{Field 'pointer' is non-null}}
George Karpenkov2c2d0b62019-01-18 19:24:55 +0000655 // expected-note@os_smart_ptr.h:35{{Taking true branch}}
656 // expected-note@os_smart_ptr.h:36{{Calling 'smart_ptr::_release'}}
George Karpenkov0f3bbba2019-01-29 19:29:07 +0000657 // 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 +0000658 // expected-note@os_smart_ptr.h:36{{Returning from 'smart_ptr::_release'}}
Csaba Dabisd1f0ec32019-05-29 20:29:02 +0000659 // expected-note@-6{{Returning from '~smart_ptr'}}
George Karpenkov2c2d0b62019-01-18 19:24:55 +0000660} // expected-warning{{Potential leak of an object stored into 'obj'}}
661// 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}}
662
663void test_smart_ptr_no_leak() {
664 OSObject *obj = new OSObject;
665 {
666 OSObjectPtr p(obj);
667 }
668 obj->release();
669}
670
George Karpenkovd37ff4e2019-01-29 19:29:59 +0000671OSObject *getRuleViolation() {
672 return new OSObject; // expected-warning{{Potential leak of an object of type 'OSObject'}}
673// expected-note@-1{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
674// expected-note@-2{{Object leaked: allocated object of type 'OSObject' is returned from a function whose name ('getRuleViolation') starts with 'get'}}
675}
676
677OSObject *createRuleViolation(OSObject *param) { // expected-note{{Parameter 'param' starts at +0}}
678 return param; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
679 // expected-note@-1{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
680}
681
George Karpenkov2c2d0b62019-01-18 19:24:55 +0000682void test_ostypealloc_correct_diagnostic_name() {
683 OSArray *arr = OSTypeAlloc(OSArray); // expected-note{{Call to method 'OSMetaClass::alloc' returns an OSObject of type 'OSArray' with a +1 retain count}}
684 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
685 arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}}
686} // 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}}
687 // expected-warning@-1{{Potential leak of an object stored into 'arr'}}
688
689void escape_elsewhere(OSObject *obj);
690
691void test_free_on_escaped_object_diagnostics() {
692 OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
693 escape_elsewhere(obj); // expected-note{{Object is now not exclusively owned}}
694 obj->free(); // expected-note{{'free' called on an object that may be referenced elsewhere}}
695 // expected-warning@-1{{'free' called on an object that may be referenced elsewhere}}
696}
697
George Karpenkov0f3bbba2019-01-29 19:29:07 +0000698void test_tagged_retain_no_leak() {
699 OSObject *obj = new OSObject;
700 obj->taggedRelease();
701}
702
703void test_tagged_retain_no_uaf() {
704 OSObject *obj = new OSObject;
705 obj->taggedRetain();
706 obj->release();
707 obj->release();
708}
Artem Dergachev48e7a2f2019-04-26 02:05:18 +0000709
710class IOService {
711public:
712 OSObject *somethingMatching(OSObject *table = 0);
713};
714
715OSObject *testSuppressionForMethodsEndingWithMatching(IOService *svc,
716 OSObject *table = 0) {
717 // This probably just passes table through. We should probably not make
718 // ptr1 definitely equal to table, but we should not warn about leaks.
719 OSObject *ptr1 = svc->somethingMatching(table); // no-warning
720
721 // FIXME: This, however, should follow the Create Rule regardless.
722 // We should warn about the leak here.
723 OSObject *ptr2 = svc->somethingMatching(); // no-warning
724
725 if (!table)
726 table = OSTypeAlloc(OSArray);
727
728 // This function itself ends with "Matching"! Do not warn when we're
729 // returning from it at +0.
730 return table; // no-warning
731}
Artem Dergachev07c72572019-05-15 18:41:32 +0000732
733namespace weird_result {
734struct WeirdResult {
735 int x, y, z;
736};
737
738WeirdResult outParamWithWeirdResult(OS_RETURNS_RETAINED_ON_ZERO OSObject **obj);
739
740WeirdResult testOutParamWithWeirdResult() {
741 OSObject *obj;
742 return outParamWithWeirdResult(&obj); // no-warning
743}
744} // namespace weird_result
Artem Dergacheva82ffe9d2020-02-17 21:42:50 +0300745
746namespace inherited_constructor_crash {
747struct a {
748 a(int);
749};
750struct b : a {
751 // This is an "inherited constructor".
752 using a::a;
753};
754void test() {
755 // RetainCountChecker used to crash when looking for a summary
756 // for the inherited constructor invocation.
757 b(0);
758}
759} // namespace inherited_constructor_crash
Artem Dergachev3500cc82020-04-01 18:15:00 +0300760
761namespace ossymbol_suppression {
762OSSymbol *createSymbol();
763void test() {
764 OSSymbol *sym = createSymbol(); // no-warning
765}
766} // namespace ossymbol_suppression