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 
generateArrayHasCodeOSArray29   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 
consumeArrayHasCodeOSArray36   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 // These are never refcounted.
57 struct OSSymbol : OSObject {};
58 
59 struct OtherStruct {
60   static void doNothingToArray(OSArray *array);
61   OtherStruct(OSArray *arr);
62 };
63 
test_meta_cast_no_leak(OSMetaClassBase * arg)64 bool test_meta_cast_no_leak(OSMetaClassBase *arg) {
65   return arg && arg->metaCast("blah") != nullptr;
66 }
67 
consumedMismatch(OS_CONSUME OSObject * a,OSObject * b)68 static 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 
75 void escape(void *);
escape_with_source(void * p)76 void escape_with_source(void *p) {}
77 bool coin();
78 
79 typedef int kern_return_t;
80 typedef kern_return_t IOReturn;
81 typedef kern_return_t OSReturn;
82 #define kOSReturnSuccess  0
83 #define kIOReturnSuccess 0
84 
85 bool write_into_out_param_on_success(OS_RETURNS_RETAINED OSObject **obj);
86 
use_out_param()87 void use_out_param() {
88   OSObject *obj;
89   if (write_into_out_param_on_success(&obj)) {
90     obj->release();
91   }
92 }
93 
use_out_param_leak()94 void 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 
100 bool write_into_out_param_on_failure(OS_RETURNS_RETAINED_ON_ZERO OSObject **obj);
101 
use_out_param_leak2()102 void 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 
use_out_param_on_failure()108 void use_out_param_on_failure() {
109   OSObject *obj;
110   if (!write_into_out_param_on_failure(&obj)) {
111     obj->release();
112   }
113 }
114 
115 IOReturn write_into_out_param_on_nonzero(OS_RETURNS_RETAINED_ON_NONZERO OSObject **obj);
116 
use_out_param_on_nonzero()117 void use_out_param_on_nonzero() {
118   OSObject *obj;
119   if (write_into_out_param_on_nonzero(&obj) != kIOReturnSuccess) {
120     obj->release();
121   }
122 }
123 
124 bool write_into_two_out_params(OS_RETURNS_RETAINED OSObject **a,
125                                OS_RETURNS_RETAINED OSObject **b);
126 
use_write_into_two_out_params()127 void 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 
use_write_two_out_params_leak()136 void 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 
146 void always_write_into_two_out_params(OS_RETURNS_RETAINED OSObject **a,
147                                       OS_RETURNS_RETAINED OSObject **b);
148 
use_always_write_into_two_out_params()149 void 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 
use_always_write_into_two_out_params_leak()157 void 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 
167 char *write_into_out_param_on_nonnull(OS_RETURNS_RETAINED OSObject **obj);
168 
use_out_param_osreturn_on_nonnull()169 void use_out_param_osreturn_on_nonnull() {
170   OSObject *obj;
171   if (write_into_out_param_on_nonnull(&obj)) {
172     obj->release();
173   }
174 }
175 
use_out_param_leak_osreturn_on_nonnull()176 void 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 
182 bool write_optional_out_param(OS_RETURNS_RETAINED OSObject **obj=nullptr);
183 
use_optional_out_param()184 void use_optional_out_param() {
185   if (write_optional_out_param()) {};
186 }
187 
188 OSReturn write_into_out_param_on_os_success(OS_RETURNS_RETAINED OSObject **obj);
189 
190 void write_into_non_retained_out_param(OS_RETURNS_NOT_RETAINED OSObject **obj);
191 
use_write_into_non_retained_out_param()192 void use_write_into_non_retained_out_param() {
193   OSObject *obj;
194   write_into_non_retained_out_param(&obj);
195 }
196 
use_write_into_non_retained_out_param_uaf()197 void 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 
204 void always_write_into_out_param(OS_RETURNS_RETAINED OSObject **obj);
205 
pass_through_out_param(OSObject ** obj)206 void pass_through_out_param(OSObject **obj) {
207   always_write_into_out_param(obj);
208 }
209 
always_write_into_out_param_has_source(OS_RETURNS_RETAINED OSObject ** obj)210 void 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 
use_always_write_into_out_param_has_source_leak()214 void 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 
use_void_out_param_osreturn()221 void use_void_out_param_osreturn() {
222   OSObject *obj;
223   always_write_into_out_param(&obj);
224   obj->release();
225 }
226 
use_void_out_param_osreturn_leak()227 void 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 
use_out_param_osreturn()233 void use_out_param_osreturn() {
234   OSObject *obj;
235   if (write_into_out_param_on_os_success(&obj) == kOSReturnSuccess) {
236     obj->release();
237   }
238 }
239 
use_out_param_leak_osreturn()240 void 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 
246 void cleanup(OSObject **obj);
247 
test_cleanup_escaping()248 void test_cleanup_escaping() {
249   __attribute__((cleanup(cleanup))) OSObject *obj;
250   always_write_into_out_param(&obj); // no-warning, the value has escaped.
251 }
252 
253 struct StructWithField {
254   OSObject *obj;
255 
initViaOutParamCallStructWithField256   void initViaOutParamCall() { // no warning on writing into fields
257     always_write_into_out_param(&obj);
258   }
259 
260 };
261 
os_consume_violation_two_args(OS_CONSUME OSObject * obj,bool extra)262 bool 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   }
268   return false; // expected-note{{Parameter 'obj' is marked as consuming, but the function did not consume the reference}}
269 }
270 
os_consume_violation(OS_CONSUME OSObject * obj)271 bool 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   }
277   return false; // expected-note{{Parameter 'obj' is marked as consuming, but the function did not consume the reference}}
278 }
279 
os_consume_ok(OS_CONSUME OSObject * obj)280 void os_consume_ok(OS_CONSUME OSObject *obj) {
281   escape(obj);
282 }
283 
use_os_consume_violation()284 void use_os_consume_violation() {
285   OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
286   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 
use_os_consume_violation_two_args()291 void use_os_consume_violation_two_args() {
292   OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type 'OSObject' with a +1 retain count}}
293   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 
use_os_consume_ok()298 void use_os_consume_ok() {
299   OSObject *obj = new OSObject;
300   os_consume_ok(obj);
301 }
302 
test_escaping_into_voidstar()303 void test_escaping_into_voidstar() {
304   OSObject *obj = new OSObject;
305   escape(obj);
306 }
307 
test_escape_has_source()308 void test_escape_has_source() {
309   OSObject *obj = new OSObject;
310   if (obj)
311     escape_with_source(obj);
312   return;
313 }
314 
test_no_infinite_check_recursion(MyArray * arr)315 void 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 
check_param_attribute_propagation(MyArray * parent)323 void check_param_attribute_propagation(MyArray *parent) {
324   OSArray *arr = new OSArray;
325   parent->consumeReference(arr);
326 }
327 
check_attribute_propagation(OSArray * arr)328 unsigned 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 
check_attribute_indirect_propagation(MyArray * arr)336 unsigned 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 
check_consumes_this(OSArray * owner)344 void check_consumes_this(OSArray *owner) {
345   OSArray *arr = new OSArray;
346   arr->putIntoArray(owner);
347 }
348 
check_consumes_this_with_template(OSArray * owner)349 void check_consumes_this_with_template(OSArray *owner) {
350   OSArray *arr = new OSArray;
351   arr->putIntoT(owner);
352 }
353 
check_free_no_error()354 void check_free_no_error() {
355   OSArray *arr = OSArray::withCapacity(10);
356   arr->retain();
357   arr->retain();
358   arr->retain();
359   arr->free();
360 }
361 
check_free_use_after_free()362 void check_free_use_after_free() {
363   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}
364   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 
check_leak_explicit_new()370 unsigned int check_leak_explicit_new() {
371   OSArray *arr = new OSArray; // expected-note{{Operator 'new' returns an OSObject of type 'OSArray' with a +1 retain count}}
372   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'}}
374 }
375 
check_leak_factory()376 unsigned int check_leak_factory() {
377   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}
378   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 
check_get_object()382 void check_get_object() {
383   OSObject::getObject();
384 }
385 
check_Get_object()386 void check_Get_object() {
387   OSObject::GetObject();
388 }
389 
check_custom_iterator_rule(OSArray * arr)390 void check_custom_iterator_rule(OSArray *arr) {
391   OSIterator *it = arr->getIterator();
392   it->release();
393 }
394 
check_iterator_leak(OSArray * arr)395 void check_iterator_leak(OSArray *arr) {
396   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}}'
399 
check_no_invalidation()400 void check_no_invalidation() {
401   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}
402   OtherStruct::doNothingToArray(arr);
403 } // expected-warning{{Potential leak of an object stored into 'arr'}}
404   // expected-note@-1{{Object leaked}}
405 
check_no_invalidation_other_struct()406 void check_no_invalidation_other_struct() {
407   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}
408   OtherStruct other(arr); // expected-warning{{Potential leak}}
409                           // expected-note@-1{{Object leaked}}
410 }
411 
412 struct ArrayOwner : public OSObject {
413   OSArray *arr;
ArrayOwnerArrayOwner414   ArrayOwner(OSArray *arr) : arr(arr) {}
415 
createArrayOwner416   static ArrayOwner* create(OSArray *arr) {
417     return new ArrayOwner(arr);
418   }
419 
getArrayArrayOwner420   OSArray *getArray() {
421     return arr;
422   }
423 
createArrayArrayOwner424   OSArray *createArray() {
425     return OSArray::withCapacity(10);
426   }
427 
428   OSArray *createArraySourceUnknown();
429 
430   OSArray *getArraySourceUnknown();
431 };
432 
generateArray()433 OSArray *generateArray() {
434   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}}
436 }
437 
check_leak_good_error_message()438 unsigned 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 
check_leak_msg_temporary()449 unsigned int check_leak_msg_temporary() {
450   return generateArray()->getCount(); // expected-warning{{Potential leak of an object}}
451                                       // expected-note@-1{{Calling 'generateArray'}}
452                                       // expected-note@-2{{Returning from 'generateArray'}}
453                                       // 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}}
454 }
455 
check_confusing_getters()456 void 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 
check_rc_consumed()466 void check_rc_consumed() {
467   OSArray *arr = OSArray::withCapacity(10);
468   OSArray::consumeArray(arr);
469 }
470 
check_rc_consume_temporary()471 void check_rc_consume_temporary() {
472   OSArray::consumeArray(OSArray::withCapacity(10));
473 }
474 
check_rc_getter()475 void check_rc_getter() {
476   OSArray *arr = OSArray::MaskedGetter();
477   (void)arr;
478 }
479 
check_rc_create()480 void check_rc_create() {
481   OSArray *arr = OSArray::getOoopsActuallyCreate();
482   arr->release();
483 }
484 
485 
check_dynamic_cast()486 void check_dynamic_cast() {
487   OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1));
488   arr->release();
489 }
490 
check_required_cast()491 void check_required_cast() {
492   OSArray *arr = OSRequiredCast(OSArray, OSObject::generateObject(1));
493   arr->release(); // no-warning
494 }
495 
check_cast_behavior(OSObject * obj)496 void 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 
check_dynamic_cast_no_null_on_orig(OSObject * obj)508 unsigned 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 
check_dynamic_cast_null_branch(OSObject * obj)520 void check_dynamic_cast_null_branch(OSObject *obj) {
521   OSArray *arr1 = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject}}
522   OSArray *arr = OSDynamicCast(OSArray, obj); // expected-note{{Assuming dynamic cast returns null due to type mismatch}}
523   if (!arr) // expected-note{{'arr' is null}}
524             // expected-note@-1{{Taking true branch}}
525     return; // expected-warning{{Potential leak of an object stored into 'arr1'}}
526             // expected-note@-1{{Object leaked}}
527   arr1->release();
528 }
529 
check_dynamic_cast_null_check()530 void check_dynamic_cast_null_check() {
531   OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); // expected-note{{Call to method 'OSObject::generateObject' returns an OSObject}}
532     // expected-warning@-1{{Potential leak of an object}}
533     // expected-note@-2{{Object leaked}}
534     // expected-note@-3{{Assuming dynamic cast returns null due to type mismatch}}
535   if (!arr)
536     return;
537   arr->release();
538 }
539 
use_after_release()540 void use_after_release() {
541   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}
542   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 
potential_leak()547 void potential_leak() {
548   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type 'OSArray' with a +1 retain count}}
549   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 
proper_cleanup()555 void 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 
no_warning_on_getter(ArrayOwner * owner)563 unsigned int no_warning_on_getter(ArrayOwner *owner) {
564   OSArray *arr = owner->getArray();
565   return arr->getCount();
566 }
567 
warn_on_overrelease(ArrayOwner * owner)568 unsigned int warn_on_overrelease(ArrayOwner *owner) {
569   // 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();
574   return arr->getCount();
575 }
576 
nowarn_on_release_of_created(ArrayOwner * owner)577 unsigned 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 
nowarn_on_release_of_created_source_unknown(ArrayOwner * owner)584 unsigned 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 
no_warn_ok_release(ArrayOwner * owner)591 unsigned 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 
warn_on_overrelease_with_unknown_source(ArrayOwner * owner)598 unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) {
599   OSArray *arr = owner->getArraySourceUnknown(); // expected-note{{Call to method 'ArrayOwner::getArraySourceUnknown' returns an OSObject of type 'OSArray' with a +0 retain count}}
600   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 
ok_release_with_unknown_source(ArrayOwner * owner)605 unsigned 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 }
611 
612 OSObject *getObject();
613 typedef bool (^Blk)(OSObject *);
614 
test_escape_to_unknown_block(Blk blk)615 void test_escape_to_unknown_block(Blk blk) {
616   blk(getObject()); // no-crash
617 }
618 
619 using OSObjectPtr = os::smart_ptr<OSObject>;
620 
test_smart_ptr_uaf()621 void 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>'}}
626     // expected-note@os_smart_ptr.h:13{{Field 'pointer' is non-null}}
627     // expected-note@os_smart_ptr.h:13{{Taking true branch}}
628     // expected-note@os_smart_ptr.h:14{{Calling 'smart_ptr::_retain'}}
629     // expected-note@os_smart_ptr.h:71{{Reference count incremented. The object now has a +2 retain count}}
630     // expected-note@os_smart_ptr.h:14{{Returning from 'smart_ptr::_retain'}}
631   } // expected-note{{Calling '~smart_ptr'}}
632   // expected-note@os_smart_ptr.h:35{{Field 'pointer' is non-null}}
633   // expected-note@os_smart_ptr.h:35{{Taking true branch}}
634   // expected-note@os_smart_ptr.h:36{{Calling 'smart_ptr::_release'}}
635   // expected-note@os_smart_ptr.h:76{{Reference count decremented. The object now has a +1 retain count}}
636   // expected-note@os_smart_ptr.h:36{{Returning from 'smart_ptr::_release'}}
637  // expected-note@-6{{Returning from '~smart_ptr'}}
638   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 
test_smart_ptr_leak()643 void 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>'}}
648     // expected-note@os_smart_ptr.h:13{{Field 'pointer' is non-null}}
649     // expected-note@os_smart_ptr.h:13{{Taking true branch}}
650     // expected-note@os_smart_ptr.h:14{{Calling 'smart_ptr::_retain'}}
651     // expected-note@os_smart_ptr.h:71{{Reference count incremented. The object now has a +2 retain count}}
652     // expected-note@os_smart_ptr.h:14{{Returning from 'smart_ptr::_retain'}}
653   } // expected-note{{Calling '~smart_ptr'}}
654   // expected-note@os_smart_ptr.h:35{{Field 'pointer' is non-null}}
655   // expected-note@os_smart_ptr.h:35{{Taking true branch}}
656   // expected-note@os_smart_ptr.h:36{{Calling 'smart_ptr::_release'}}
657   // expected-note@os_smart_ptr.h:76{{Reference count decremented. The object now has a +1 retain count}}
658   // expected-note@os_smart_ptr.h:36{{Returning from 'smart_ptr::_release'}}
659  // expected-note@-6{{Returning from '~smart_ptr'}}
660 } // 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 
test_smart_ptr_no_leak()663 void test_smart_ptr_no_leak() {
664   OSObject *obj = new OSObject;
665   {
666     OSObjectPtr p(obj);
667   }
668   obj->release();
669 }
670 
getRuleViolation()671 OSObject *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 
createRuleViolation(OSObject * param)677 OSObject *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 
test_ostypealloc_correct_diagnostic_name()682 void 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 
689 void escape_elsewhere(OSObject *obj);
690 
test_free_on_escaped_object_diagnostics()691 void 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 
test_tagged_retain_no_leak()698 void test_tagged_retain_no_leak() {
699   OSObject *obj = new OSObject;
700   obj->taggedRelease();
701 }
702 
test_tagged_retain_no_uaf()703 void test_tagged_retain_no_uaf() {
704   OSObject *obj = new OSObject;
705   obj->taggedRetain();
706   obj->release();
707   obj->release();
708 }
709 
710 class IOService {
711 public:
712   OSObject *somethingMatching(OSObject *table = 0);
713 };
714 
testSuppressionForMethodsEndingWithMatching(IOService * svc,OSObject * table=0)715 OSObject *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 }
732 
733 namespace weird_result {
734 struct WeirdResult {
735   int x, y, z;
736 };
737 
738 WeirdResult outParamWithWeirdResult(OS_RETURNS_RETAINED_ON_ZERO OSObject **obj);
739 
testOutParamWithWeirdResult()740 WeirdResult testOutParamWithWeirdResult() {
741   OSObject *obj;
742   return outParamWithWeirdResult(&obj); // no-warning
743 }
744 } // namespace weird_result
745 
746 namespace inherited_constructor_crash {
747 struct a {
748   a(int);
749 };
750 struct b : a {
751   // This is an "inherited constructor".
752   using a::a;
753 };
test()754 void 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
760 
761 namespace ossymbol_suppression {
762 OSSymbol *createSymbol();
test()763 void test() {
764   OSSymbol *sym = createSymbol(); // no-warning
765 }
766 } // namespace ossymbol_suppression
767