1 // RUN: %clang_analyze_cc1 -fblocks -analyze -analyzer-output=text\
2 // RUN:                    -analyzer-checker=core,osx -verify %s
3 
4 #include "os_object_base.h"
5 #include "os_smart_ptr.h"
6 
7 struct OSIterator : public OSObject {
8   static const OSMetaClass * const metaClass;
9 };
10 
11 struct OSArray : public OSObject {
12   unsigned int getCount();
13 
14   OSIterator * getIterator();
15 
16   OSObject *identity() override;
17 
18   virtual OSObject *generateObject(OSObject *input);
19 
20   virtual void consumeReference(OS_CONSUME OSArray *other);
21 
22   void putIntoArray(OSArray *array) OS_CONSUMES_THIS;
23 
24   template <typename T>
25   void putIntoT(T *owner) OS_CONSUMES_THIS;
26 
27   static OSArray *generateArrayHasCode() {
28     return new OSArray;
29   }
30 
31   static OSArray *withCapacity(unsigned int capacity);
32   static void consumeArray(OS_CONSUME OSArray * array);
33 
34   static OSArray* consumeArrayHasCode(OS_CONSUME OSArray * array) { // expected-note{{Parameter 'array' starts at +1, as it is marked as consuming}}
35     return nullptr; // expected-warning{{Potential leak of an object of type 'OSArray'}}
36 // 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}}
37   }
38 
39 
40   static OS_RETURNS_NOT_RETAINED OSArray *MaskedGetter();
41   static OS_RETURNS_RETAINED OSArray *getOoopsActuallyCreate();
42 
43   static const OSMetaClass * const metaClass;
44 };
45 
46 struct MyArray : public OSArray {
47   void consumeReference(OSArray *other) override;
48 
49   OSObject *identity() override;
50 
51   OSObject *generateObject(OSObject *input) override;
52 };
53 
54 struct OtherStruct {
55   static void doNothingToArray(OSArray *array);
56   OtherStruct(OSArray *arr);
57 };
58 
59 bool test_meta_cast_no_leak(OSMetaClassBase *arg) {
60   return arg && arg->metaCast("blah") != nullptr;
61 }
62 
63 static void consumedMismatch(OS_CONSUME OSObject *a,
64                              OSObject *b) { // expected-note{{Parameter 'b' starts at +0}}
65   a->release();
66   b->retain(); // expected-note{{Reference count incremented. The object now has a +1 retain count}}
67 } // expected-warning{{Potential leak of an object of type 'OSObject'}}
68 // 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}}
69 
70 void escape(void *);
71 void escape_with_source(void *p) {}
72 bool coin();
73 
74 typedef int kern_return_t;
75 typedef kern_return_t IOReturn;
76 typedef kern_return_t OSReturn;
77 #define kOSReturnSuccess  0
78 #define kIOReturnSuccess 0
79 
80 bool write_into_out_param_on_success(OS_RETURNS_RETAINED OSObject **obj);
81 
82 void use_out_param() {
83   OSObject *obj;
84   if (write_into_out_param_on_success(&obj)) {
85     obj->release();
86   }
87 }
88 
89 void use_out_param_leak() {
90   OSObject *obj;
91   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){{$}}}}
92 } // expected-warning{{Potential leak of an object stored into 'obj'}}
93  // 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}}
94 
95 bool write_into_out_param_on_failure(OS_RETURNS_RETAINED_ON_ZERO OSObject **obj);
96 
97 void use_out_param_leak2() {
98   OSObject *obj;
99   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){{$}}}}
100 } // expected-warning{{Potential leak of an object stored into 'obj'}}
101  // 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}}
102 
103 void use_out_param_on_failure() {
104   OSObject *obj;
105   if (!write_into_out_param_on_failure(&obj)) {
106     obj->release();
107   }
108 }
109 
110 IOReturn write_into_out_param_on_nonzero(OS_RETURNS_RETAINED_ON_NONZERO OSObject **obj);
111 
112 void use_out_param_on_nonzero() {
113   OSObject *obj;
114   if (write_into_out_param_on_nonzero(&obj) != kIOReturnSuccess) {
115     obj->release();
116   }
117 }
118 
119 bool write_into_two_out_params(OS_RETURNS_RETAINED OSObject **a,
120                                OS_RETURNS_RETAINED OSObject **b);
121 
122 void use_write_into_two_out_params() {
123   OSObject *obj1;
124   OSObject *obj2;
125   if (write_into_two_out_params(&obj1, &obj2)) {
126     obj1->release();
127     obj2->release();
128   }
129 }
130 
131 void use_write_two_out_params_leak() {
132   OSObject *obj1;
133   OSObject *obj2;
134   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){{$}}}}
135                                            // 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){{$}}}}
136 } // expected-warning{{Potential leak of an object stored into 'obj1'}}
137   // expected-warning@-1{{Potential leak of an object stored into 'obj2'}}
138   // 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}}
139   // 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}}
140 
141 void always_write_into_two_out_params(OS_RETURNS_RETAINED OSObject **a,
142                                       OS_RETURNS_RETAINED OSObject **b);
143 
144 void use_always_write_into_two_out_params() {
145   OSObject *obj1;
146   OSObject *obj2;
147   always_write_into_two_out_params(&obj1, &obj2);
148   obj1->release();
149   obj2->release();
150 }
151 
152 void use_always_write_into_two_out_params_leak() {
153   OSObject *obj1;
154   OSObject *obj2;
155   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'{{$}}}}
156                                                   // 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'{{$}}}}
157 } // expected-warning{{Potential leak of an object stored into 'obj1'}}
158   // expected-warning@-1{{Potential leak of an object stored into 'obj2'}}
159   // 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}}
160   // 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}}
161 
162 char *write_into_out_param_on_nonnull(OS_RETURNS_RETAINED OSObject **obj);
163 
164 void use_out_param_osreturn_on_nonnull() {
165   OSObject *obj;
166   if (write_into_out_param_on_nonnull(&obj)) {
167     obj->release();
168   }
169 }
170 
171 void use_out_param_leak_osreturn_on_nonnull() {
172   OSObject *obj;
173   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){{$}}}}
174 } // expected-warning{{Potential leak of an object stored into 'obj'}}
175   // 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}}
176 
177 bool write_optional_out_param(OS_RETURNS_RETAINED OSObject **obj=nullptr);
178 
179 void use_optional_out_param() {
180   if (write_optional_out_param()) {};
181 }
182 
183 OSReturn write_into_out_param_on_os_success(OS_RETURNS_RETAINED OSObject **obj);
184 
185 void write_into_non_retained_out_param(OS_RETURNS_NOT_RETAINED OSObject **obj);
186 
187 void use_write_into_non_retained_out_param() {
188   OSObject *obj;
189   write_into_non_retained_out_param(&obj);
190 }
191 
192 void use_write_into_non_retained_out_param_uaf() {
193   OSObject *obj;
194   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'{{$}}}}
195   obj->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
196                   // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
197 }
198 
199 void always_write_into_out_param(OS_RETURNS_RETAINED OSObject **obj);
200 
201 void pass_through_out_param(OSObject **obj) {
202   always_write_into_out_param(obj);
203 }
204 
205 void always_write_into_out_param_has_source(OS_RETURNS_RETAINED OSObject **obj) {
206   *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
207 }
208 
209 void use_always_write_into_out_param_has_source_leak() {
210   OSObject *obj;
211   always_write_into_out_param_has_source(&obj); // expected-note{{Calling 'always_write_into_out_param_has_source'}}
212                                                 // expected-note@-1{{Returning from 'always_write_into_out_param_has_source'}}
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 
216 void use_void_out_param_osreturn() {
217   OSObject *obj;
218   always_write_into_out_param(&obj);
219   obj->release();
220 }
221 
222 void use_void_out_param_osreturn_leak() {
223   OSObject *obj;
224   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'{{$}}}}
225 } // expected-warning{{Potential leak of an object stored into 'obj'}}
226   // 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}}
227 
228 void use_out_param_osreturn() {
229   OSObject *obj;
230   if (write_into_out_param_on_os_success(&obj) == kOSReturnSuccess) {
231     obj->release();
232   }
233 }
234 
235 void use_out_param_leak_osreturn() {
236   OSObject *obj;
237   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){{$}}}}
238 } // expected-warning{{Potential leak of an object stored into 'obj'}}
239   // expected-note@-1{{Object leaked: object allocated and stored into 'obj' is not referenced later in this execution path and has a retain count of +1}}
240 
241 void cleanup(OSObject **obj);
242 
243 void test_cleanup_escaping() {
244   __attribute__((cleanup(cleanup))) OSObject *obj;
245   always_write_into_out_param(&obj); // no-warning, the value has escaped.
246 }
247 
248 struct StructWithField {
249   OSObject *obj;
250 
251   void initViaOutParamCall() { // no warning on writing into fields
252     always_write_into_out_param(&obj);
253   }
254 
255 };
256 
257 bool os_consume_violation_two_args(OS_CONSUME OSObject *obj, bool extra) {
258   if (coin()) { // expected-note{{Assuming the condition is false}}
259                 // expected-note@-1{{Taking false branch}}
260     escape(obj);
261     return true;
262   }
263   return false; // expected-note{{Parameter 'obj' is marked as consuming, but the function did not consume the reference}}
264 }
265 
266 bool os_consume_violation(OS_CONSUME OSObject *obj) {
267   if (coin()) { // expected-note{{Assuming the condition is false}}
268                 // expected-note@-1{{Taking false branch}}
269     escape(obj);
270     return true;
271   }
272   return false; // expected-note{{Parameter 'obj' is marked as consuming, but the function did not consume the reference}}
273 }
274 
275 void os_consume_ok(OS_CONSUME OSObject *obj) {
276   escape(obj);
277 }
278 
279 void use_os_consume_violation() {
280   OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
281   os_consume_violation(obj); // expected-note{{Calling 'os_consume_violation'}}
282                              // expected-note@-1{{Returning from 'os_consume_violation'}}
283 } // 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}}
284   // expected-warning@-1{{Potential leak of an object stored into 'obj'}}
285 
286 void use_os_consume_violation_two_args() {
287   OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
288   os_consume_violation_two_args(obj, coin()); // expected-note{{Calling 'os_consume_violation_two_args'}}
289                              // expected-note@-1{{Returning from 'os_consume_violation_two_args'}}
290 } // 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}}
291   // expected-warning@-1{{Potential leak of an object stored into 'obj'}}
292 
293 void use_os_consume_ok() {
294   OSObject *obj = new OSObject;
295   os_consume_ok(obj);
296 }
297 
298 void test_escaping_into_voidstar() {
299   OSObject *obj = new OSObject;
300   escape(obj);
301 }
302 
303 void test_escape_has_source() {
304   OSObject *obj = new OSObject;
305   if (obj)
306     escape_with_source(obj);
307   return;
308 }
309 
310 void test_no_infinite_check_recursion(MyArray *arr) {
311   OSObject *input = new OSObject;
312   OSObject *o = arr->generateObject(input);
313   o->release();
314   input->release();
315 }
316 
317 
318 void check_param_attribute_propagation(MyArray *parent) {
319   OSArray *arr = new OSArray;
320   parent->consumeReference(arr);
321 }
322 
323 unsigned int check_attribute_propagation(OSArray *arr) {
324   OSObject *other = arr->identity();
325   OSArray *casted = OSDynamicCast(OSArray, other);
326   if (casted)
327     return casted->getCount();
328   return 0;
329 }
330 
331 unsigned int check_attribute_indirect_propagation(MyArray *arr) {
332   OSObject *other = arr->identity();
333   OSArray *casted = OSDynamicCast(OSArray, other);
334   if (casted)
335     return casted->getCount();
336   return 0;
337 }
338 
339 void check_consumes_this(OSArray *owner) {
340   OSArray *arr = new OSArray;
341   arr->putIntoArray(owner);
342 }
343 
344 void check_consumes_this_with_template(OSArray *owner) {
345   OSArray *arr = new OSArray;
346   arr->putIntoT(owner);
347 }
348 
349 void check_free_no_error() {
350   OSArray *arr = OSArray::withCapacity(10);
351   arr->retain();
352   arr->retain();
353   arr->retain();
354   arr->free();
355 }
356 
357 void check_free_use_after_free() {
358   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}
359   arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
360   arr->free(); // expected-note{{Object released}}
361   arr->retain(); // expected-warning{{Reference-counted object is used after it is released}}
362                  // expected-note@-1{{Reference-counted object is used after it is released}}
363 }
364 
365 unsigned int check_leak_explicit_new() {
366   OSArray *arr = new OSArray; // expected-note{{Operator 'new' returns an OSObject of type 'OSArray' with a +1 retain count}}
367   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}}
368                           // expected-warning@-1{{Potential leak of an object stored into 'arr'}}
369 }
370 
371 unsigned int check_leak_factory() {
372   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}
373   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}}
374                           // expected-warning@-1{{Potential leak of an object stored into 'arr'}}
375 }
376 
377 void check_get_object() {
378   OSObject::getObject();
379 }
380 
381 void check_Get_object() {
382   OSObject::GetObject();
383 }
384 
385 void check_custom_iterator_rule(OSArray *arr) {
386   OSIterator *it = arr->getIterator();
387   it->release();
388 }
389 
390 void check_iterator_leak(OSArray *arr) {
391   arr->getIterator(); // expected-note{{Call to method 'OSArray::getIterator' returns an OSObject of type 'OSIterator' with a +1 retain count}}
392 } // expected-note{{Object leaked: allocated object of type 'OSIterator' is not referenced later}}
393   // expected-warning@-1{{Potential leak of an object of type 'OSIterator}}'
394 
395 void check_no_invalidation() {
396   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}
397   OtherStruct::doNothingToArray(arr);
398 } // expected-warning{{Potential leak of an object stored into 'arr'}}
399   // expected-note@-1{{Object leaked}}
400 
401 void check_no_invalidation_other_struct() {
402   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}
403   OtherStruct other(arr); // expected-warning{{Potential leak}}
404                           // expected-note@-1{{Object leaked}}
405 }
406 
407 struct ArrayOwner : public OSObject {
408   OSArray *arr;
409   ArrayOwner(OSArray *arr) : arr(arr) {}
410 
411   static ArrayOwner* create(OSArray *arr) {
412     return new ArrayOwner(arr);
413   }
414 
415   OSArray *getArray() {
416     return arr;
417   }
418 
419   OSArray *createArray() {
420     return OSArray::withCapacity(10);
421   }
422 
423   OSArray *createArraySourceUnknown();
424 
425   OSArray *getArraySourceUnknown();
426 };
427 
428 OSArray *generateArray() {
429   return OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}
430                                     // expected-note@-1{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}
431 }
432 
433 unsigned int check_leak_good_error_message() {
434   unsigned int out;
435   {
436     OSArray *leaked = generateArray(); // expected-note{{Calling 'generateArray'}}
437                                        // expected-note@-1{{Returning from 'generateArray'}}
438     out = leaked->getCount(); // expected-warning{{Potential leak of an object stored into 'leaked'}}
439                               // 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}}
440   }
441   return out;
442 }
443 
444 unsigned int check_leak_msg_temporary() {
445   return generateArray()->getCount(); // expected-warning{{Potential leak of an object}}
446                                       // expected-note@-1{{Calling 'generateArray'}}
447                                       // expected-note@-2{{Returning from 'generateArray'}}
448                                       // 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}}
449 }
450 
451 void check_confusing_getters() {
452   OSArray *arr = OSArray::withCapacity(10);
453 
454   ArrayOwner *AO = ArrayOwner::create(arr);
455   AO->getArray();
456 
457   AO->release();
458   arr->release();
459 }
460 
461 void check_rc_consumed() {
462   OSArray *arr = OSArray::withCapacity(10);
463   OSArray::consumeArray(arr);
464 }
465 
466 void check_rc_consume_temporary() {
467   OSArray::consumeArray(OSArray::withCapacity(10));
468 }
469 
470 void check_rc_getter() {
471   OSArray *arr = OSArray::MaskedGetter();
472   (void)arr;
473 }
474 
475 void check_rc_create() {
476   OSArray *arr = OSArray::getOoopsActuallyCreate();
477   arr->release();
478 }
479 
480 
481 void check_dynamic_cast() {
482   OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1));
483   arr->release();
484 }
485 
486 unsigned int check_dynamic_cast_no_null_on_orig(OSObject *obj) {
487   OSArray *arr = OSDynamicCast(OSArray, obj);
488   if (arr) {
489     return arr->getCount();
490   } else {
491 
492     // The fact that dynamic cast has failed should not imply that
493     // the input object was null.
494     return obj->foo(); // no-warning
495   }
496 }
497 
498 void check_dynamic_cast_null_branch(OSObject *obj) {
499   OSArray *arr1 = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject}}
500   OSArray *arr = OSDynamicCast(OSArray, obj); // expected-note{{Assuming dynamic cast returns null due to type mismatch}}
501   if (!arr) // expected-note{{Taking true branch}}
502     return; // expected-warning{{Potential leak of an object stored into 'arr1'}}
503             // expected-note@-1{{Object leaked}}
504   arr1->release();
505 }
506 
507 void check_dynamic_cast_null_check() {
508   OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); // expected-note{{Call to method 'OSObject::generateObject' returns an OSObject}}
509     // expected-warning@-1{{Potential leak of an object}}
510     // expected-note@-2{{Object leaked}}
511     // expected-note@-3{{Assuming dynamic cast returns null due to type mismatch}}
512   if (!arr)
513     return;
514   arr->release();
515 }
516 
517 void use_after_release() {
518   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}
519   arr->release(); // expected-note{{Object released}}
520   arr->getCount(); // expected-warning{{Reference-counted object is used after it is released}}
521                    // expected-note@-1{{Reference-counted object is used after it is released}}
522 }
523 
524 void potential_leak() {
525   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}
526   arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
527   arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}}
528   arr->getCount();
529 } // expected-warning{{Potential leak of an object stored into 'arr'}}
530   // 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}}
531 
532 void proper_cleanup() {
533   OSArray *arr = OSArray::withCapacity(10); // +1
534   arr->retain(); // +2
535   arr->release(); // +1
536   arr->getCount();
537   arr->release(); // 0
538 }
539 
540 unsigned int no_warning_on_getter(ArrayOwner *owner) {
541   OSArray *arr = owner->getArray();
542   return arr->getCount();
543 }
544 
545 unsigned int warn_on_overrelease(ArrayOwner *owner) {
546   // FIXME: summaries are not applied in case the source of the getter/setter
547   // is known.
548   // rdar://45681203
549   OSArray *arr = owner->getArray();
550   arr->release();
551   return arr->getCount();
552 }
553 
554 unsigned int nowarn_on_release_of_created(ArrayOwner *owner) {
555   OSArray *arr = owner->createArray();
556   unsigned int out = arr->getCount();
557   arr->release();
558   return out;
559 }
560 
561 unsigned int nowarn_on_release_of_created_source_unknown(ArrayOwner *owner) {
562   OSArray *arr = owner->createArraySourceUnknown();
563   unsigned int out = arr->getCount();
564   arr->release();
565   return out;
566 }
567 
568 unsigned int no_warn_ok_release(ArrayOwner *owner) {
569   OSArray *arr = owner->getArray(); // +0
570   arr->retain(); // +1
571   arr->release(); // +0
572   return arr->getCount(); // no-warning
573 }
574 
575 unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) {
576   OSArray *arr = owner->getArraySourceUnknown(); // expected-note{{Call to method 'ArrayOwner::getArraySourceUnknown' returns an OSObject of type 'OSArray' with a +0 retain count}}
577   arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
578                   // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
579   return arr->getCount();
580 }
581 
582 unsigned int ok_release_with_unknown_source(ArrayOwner *owner) {
583   OSArray *arr = owner->getArraySourceUnknown(); // +0
584   arr->retain(); // +1
585   arr->release(); // +0
586   return arr->getCount();
587 }
588 
589 OSObject *getObject();
590 typedef bool (^Blk)(OSObject *);
591 
592 void test_escape_to_unknown_block(Blk blk) {
593   blk(getObject()); // no-crash
594 }
595 
596 using OSObjectPtr = os::smart_ptr<OSObject>;
597 
598 void test_smart_ptr_uaf() {
599   OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
600   {
601     OSObjectPtr p(obj); // expected-note{{Calling constructor for 'smart_ptr<OSObject>'}}
602    // expected-note@-1{{Returning from constructor for 'smart_ptr<OSObject>'}}
603     // expected-note@os_smart_ptr.h:13{{Taking true branch}}
604     // expected-note@os_smart_ptr.h:14{{Calling 'smart_ptr::_retain'}}
605     // expected-note@os_smart_ptr.h:71{{Reference count incremented. The object now has a +2 retain count}}
606     // expected-note@os_smart_ptr.h:14{{Returning from 'smart_ptr::_retain'}}
607   } // expected-note{{Calling '~smart_ptr'}}
608   // expected-note@os_smart_ptr.h:35{{Taking true branch}}
609   // expected-note@os_smart_ptr.h:36{{Calling 'smart_ptr::_release'}}
610   // expected-note@os_smart_ptr.h:76{{Reference count decremented. The object now has a +1 retain count}}
611   // expected-note@os_smart_ptr.h:36{{Returning from 'smart_ptr::_release'}}
612  // expected-note@-5{{Returning from '~smart_ptr'}}
613   obj->release(); // expected-note{{Object released}}
614   obj->release(); // expected-warning{{Reference-counted object is used after it is released}}
615 // expected-note@-1{{Reference-counted object is used after it is released}}
616 }
617 
618 void test_smart_ptr_leak() {
619   OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
620   {
621     OSObjectPtr p(obj); // expected-note{{Calling constructor for 'smart_ptr<OSObject>'}}
622    // expected-note@-1{{Returning from constructor for 'smart_ptr<OSObject>'}}
623     // expected-note@os_smart_ptr.h:13{{Taking true branch}}
624     // expected-note@os_smart_ptr.h:14{{Calling 'smart_ptr::_retain'}}
625     // expected-note@os_smart_ptr.h:71{{Reference count incremented. The object now has a +2 retain count}}
626     // expected-note@os_smart_ptr.h:14{{Returning from 'smart_ptr::_retain'}}
627   } // expected-note{{Calling '~smart_ptr'}}
628   // expected-note@os_smart_ptr.h:35{{Taking true branch}}
629   // expected-note@os_smart_ptr.h:36{{Calling 'smart_ptr::_release'}}
630   // expected-note@os_smart_ptr.h:76{{Reference count decremented. The object now has a +1 retain count}}
631   // expected-note@os_smart_ptr.h:36{{Returning from 'smart_ptr::_release'}}
632  // expected-note@-5{{Returning from '~smart_ptr'}}
633 } // expected-warning{{Potential leak of an object stored into 'obj'}}
634 // 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}}
635 
636 void test_smart_ptr_no_leak() {
637   OSObject *obj = new OSObject;
638   {
639     OSObjectPtr p(obj);
640   }
641   obj->release();
642 }
643 
644 OSObject *getRuleViolation() {
645   return new OSObject; // expected-warning{{Potential leak of an object of type 'OSObject'}}
646 // expected-note@-1{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
647 // expected-note@-2{{Object leaked: allocated object of type 'OSObject' is returned from a function whose name ('getRuleViolation') starts with 'get'}}
648 }
649 
650 OSObject *createRuleViolation(OSObject *param) { // expected-note{{Parameter 'param' starts at +0}}
651   return param; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
652   // expected-note@-1{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
653 }
654 
655 void test_ostypealloc_correct_diagnostic_name() {
656   OSArray *arr = OSTypeAlloc(OSArray); // expected-note{{Call to method 'OSMetaClass::alloc' returns an OSObject of type 'OSArray' with a +1 retain count}}
657   arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
658   arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}}
659 } // 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}}
660   // expected-warning@-1{{Potential leak of an object stored into 'arr'}}
661 
662 void escape_elsewhere(OSObject *obj);
663 
664 void test_free_on_escaped_object_diagnostics() {
665   OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
666   escape_elsewhere(obj); // expected-note{{Object is now not exclusively owned}}
667   obj->free(); // expected-note{{'free' called on an object that may be referenced elsewhere}}
668   // expected-warning@-1{{'free' called on an object that may be referenced elsewhere}}
669 }
670 
671 void test_tagged_retain_no_leak() {
672   OSObject *obj = new OSObject;
673   obj->taggedRelease();
674 }
675 
676 void test_tagged_retain_no_uaf() {
677   OSObject *obj = new OSObject;
678   obj->taggedRetain();
679   obj->release();
680   obj->release();
681 }
682