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