1 // RUN: %clang_analyze_cc1 -fblocks -analyze -analyzer-output=text\
2 // RUN:                    -analyzer-checker=core,osx -verify %s
3 
4 struct OSMetaClass;
5 
6 #define OS_CONSUME __attribute__((os_consumed))
7 #define OS_RETURNS_RETAINED __attribute__((os_returns_retained))
8 #define OS_RETURNS_NOT_RETAINED __attribute__((os_returns_not_retained))
9 #define OS_CONSUMES_THIS __attribute__((os_consumes_this))
10 
11 #define OSTypeID(type)   (type::metaClass)
12 
13 #define OSDynamicCast(type, inst)   \
14     ((type *) OSMetaClassBase::safeMetaCast((inst), OSTypeID(type)))
15 
16 using size_t = decltype(sizeof(int));
17 
18 struct OSObject {
19   virtual void retain();
20   virtual void release() {};
21   virtual void free();
22   virtual ~OSObject(){}
23 
24   unsigned int foo() { return 42; }
25 
26   virtual OS_RETURNS_NOT_RETAINED OSObject *identity();
27 
28   static OSObject *generateObject(int);
29 
30   static OSObject *getObject();
31   static OSObject *GetObject();
32 
33   static void * operator new(size_t size);
34 
35   static const OSMetaClass * const metaClass;
36 };
37 
38 struct OSIterator : public OSObject {
39 
40   static const OSMetaClass * const metaClass;
41 };
42 
43 struct OSArray : public OSObject {
44   unsigned int getCount();
45 
46   OSIterator * getIterator();
47 
48   OSObject *identity() override;
49 
50   virtual OSObject *generateObject(OSObject *input);
51 
52   virtual void consumeReference(OS_CONSUME OSArray *other);
53 
54   void putIntoArray(OSArray *array) OS_CONSUMES_THIS;
55 
56   template <typename T>
57   void putIntoT(T *owner) OS_CONSUMES_THIS;
58 
59   static OSArray *generateArrayHasCode() {
60     return new OSArray;
61   }
62 
63   static OSArray *withCapacity(unsigned int capacity);
64   static void consumeArray(OS_CONSUME OSArray * array);
65 
66   static OSArray* consumeArrayHasCode(OS_CONSUME OSArray * array) {
67     return nullptr;
68   }
69 
70   static OS_RETURNS_NOT_RETAINED OSArray *MaskedGetter();
71   static OS_RETURNS_RETAINED OSArray *getOoopsActuallyCreate();
72 
73   static const OSMetaClass * const metaClass;
74 };
75 
76 struct MyArray : public OSArray {
77   void consumeReference(OSArray *other) override;
78 
79   OSObject *identity() override;
80 
81   OSObject *generateObject(OSObject *input) override;
82 };
83 
84 struct OtherStruct {
85   static void doNothingToArray(OSArray *array);
86   OtherStruct(OSArray *arr);
87 };
88 
89 struct OSMetaClassBase {
90   static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta);
91 };
92 
93 void escape(void *);
94 void escape_with_source(void *p) {}
95 bool coin();
96 
97 bool os_consume_violation_two_args(OS_CONSUME OSObject *obj, bool extra) {
98   if (coin()) { // expected-note{{Assuming the condition is false}}
99                 // expected-note@-1{{Taking false branch}}
100     escape(obj);
101     return true;
102   }
103   return false; // expected-note{{Parameter 'obj' is marked as consuming, but the function did not consume the reference}}
104 }
105 
106 bool os_consume_violation(OS_CONSUME OSObject *obj) {
107   if (coin()) { // expected-note{{Assuming the condition is false}}
108                 // expected-note@-1{{Taking false branch}}
109     escape(obj);
110     return true;
111   }
112   return false; // expected-note{{Parameter 'obj' is marked as consuming, but the function did not consume the reference}}
113 }
114 
115 void os_consume_ok(OS_CONSUME OSObject *obj) {
116   escape(obj);
117 }
118 
119 void use_os_consume_violation() {
120   OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type OSObject with a +1 retain count}}
121   os_consume_violation(obj); // expected-note{{Calling 'os_consume_violation'}}
122                              // expected-note@-1{{Returning from 'os_consume_violation'}}
123 } // 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}}
124   // expected-warning@-1{{Potential leak of an object stored into 'obj'}}
125 
126 void use_os_consume_violation_two_args() {
127   OSObject *obj = new OSObject; // expected-note{{Operator 'new' returns an OSObject of type OSObject with a +1 retain count}}
128   os_consume_violation_two_args(obj, coin()); // expected-note{{Calling 'os_consume_violation_two_args'}}
129                              // expected-note@-1{{Returning from 'os_consume_violation_two_args'}}
130 } // 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}}
131   // expected-warning@-1{{Potential leak of an object stored into 'obj'}}
132 
133 void use_os_consume_ok() {
134   OSObject *obj = new OSObject;
135   os_consume_ok(obj);
136 }
137 
138 void test_escaping_into_voidstar() {
139   OSObject *obj = new OSObject;
140   escape(obj);
141 }
142 
143 void test_escape_has_source() {
144   OSObject *obj = new OSObject;
145   if (obj)
146     escape_with_source(obj);
147   return;
148 }
149 
150 void test_no_infinite_check_recursion(MyArray *arr) {
151   OSObject *input = new OSObject;
152   OSObject *o = arr->generateObject(input);
153   o->release();
154   input->release();
155 }
156 
157 
158 void check_param_attribute_propagation(MyArray *parent) {
159   OSArray *arr = new OSArray;
160   parent->consumeReference(arr);
161 }
162 
163 unsigned int check_attribute_propagation(OSArray *arr) {
164   OSObject *other = arr->identity();
165   OSArray *casted = OSDynamicCast(OSArray, other);
166   if (casted)
167     return casted->getCount();
168   return 0;
169 }
170 
171 unsigned int check_attribute_indirect_propagation(MyArray *arr) {
172   OSObject *other = arr->identity();
173   OSArray *casted = OSDynamicCast(OSArray, other);
174   if (casted)
175     return casted->getCount();
176   return 0;
177 }
178 
179 void check_consumes_this(OSArray *owner) {
180   OSArray *arr = new OSArray;
181   arr->putIntoArray(owner);
182 }
183 
184 void check_consumes_this_with_template(OSArray *owner) {
185   OSArray *arr = new OSArray;
186   arr->putIntoT(owner);
187 }
188 
189 void check_free_no_error() {
190   OSArray *arr = OSArray::withCapacity(10);
191   arr->retain();
192   arr->retain();
193   arr->retain();
194   arr->free();
195 }
196 
197 void check_free_use_after_free() {
198   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
199   arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
200   arr->free(); // expected-note{{Object released}}
201   arr->retain(); // expected-warning{{Reference-counted object is used after it is released}}
202                  // expected-note@-1{{Reference-counted object is used after it is released}}
203 }
204 
205 unsigned int check_leak_explicit_new() {
206   OSArray *arr = new OSArray; // expected-note{{Operator 'new' returns an OSObject of type OSArray with a +1 retain count}}
207   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}}
208                           // expected-warning@-1{{Potential leak of an object stored into 'arr'}}
209 }
210 
211 unsigned int check_leak_factory() {
212   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
213   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}}
214                           // expected-warning@-1{{Potential leak of an object stored into 'arr'}}
215 }
216 
217 void check_get_object() {
218   OSObject::getObject();
219 }
220 
221 void check_Get_object() {
222   OSObject::GetObject();
223 }
224 
225 void check_custom_iterator_rule(OSArray *arr) {
226   OSIterator *it = arr->getIterator();
227   it->release();
228 }
229 
230 void check_iterator_leak(OSArray *arr) {
231   arr->getIterator(); // expected-note{{Call to method 'OSArray::getIterator' returns an OSObject of type OSIterator with a +1 retain count}}
232 } // expected-note{{Object leaked: allocated object of type OSIterator is not referenced later}}
233   // expected-warning@-1{{Potential leak of an object of type OSIterator}}
234 
235 void check_no_invalidation() {
236   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
237   OtherStruct::doNothingToArray(arr);
238 } // expected-warning{{Potential leak of an object stored into 'arr'}}
239   // expected-note@-1{{Object leaked}}
240 
241 void check_no_invalidation_other_struct() {
242   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
243   OtherStruct other(arr); // expected-warning{{Potential leak}}
244                           // expected-note@-1{{Object leaked}}
245 }
246 
247 struct ArrayOwner : public OSObject {
248   OSArray *arr;
249   ArrayOwner(OSArray *arr) : arr(arr) {}
250 
251   static ArrayOwner* create(OSArray *arr) {
252     return new ArrayOwner(arr);
253   }
254 
255   OSArray *getArray() {
256     return arr;
257   }
258 
259   OSArray *createArray() {
260     return OSArray::withCapacity(10);
261   }
262 
263   OSArray *createArraySourceUnknown();
264 
265   OSArray *getArraySourceUnknown();
266 };
267 
268 OSArray *generateArray() {
269   return OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
270                                     // expected-note@-1{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
271 }
272 
273 unsigned int check_leak_good_error_message() {
274   unsigned int out;
275   {
276     OSArray *leaked = generateArray(); // expected-note{{Calling 'generateArray'}}
277                                        // expected-note@-1{{Returning from 'generateArray'}}
278     out = leaked->getCount(); // expected-warning{{Potential leak of an object stored into 'leaked'}}
279                               // 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}}
280   }
281   return out;
282 }
283 
284 unsigned int check_leak_msg_temporary() {
285   return generateArray()->getCount(); // expected-warning{{Potential leak of an object}}
286                                       // expected-note@-1{{Calling 'generateArray'}}
287                                       // expected-note@-2{{Returning from 'generateArray'}}
288                                       // 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}}
289 }
290 
291 void check_confusing_getters() {
292   OSArray *arr = OSArray::withCapacity(10);
293 
294   ArrayOwner *AO = ArrayOwner::create(arr);
295   AO->getArray();
296 
297   AO->release();
298   arr->release();
299 }
300 
301 void check_rc_consumed() {
302   OSArray *arr = OSArray::withCapacity(10);
303   OSArray::consumeArray(arr);
304 }
305 
306 void check_rc_consume_temporary() {
307   OSArray::consumeArray(OSArray::withCapacity(10));
308 }
309 
310 void check_rc_getter() {
311   OSArray *arr = OSArray::MaskedGetter();
312   (void)arr;
313 }
314 
315 void check_rc_create() {
316   OSArray *arr = OSArray::getOoopsActuallyCreate();
317   arr->release();
318 }
319 
320 
321 void check_dynamic_cast() {
322   OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1));
323   arr->release();
324 }
325 
326 unsigned int check_dynamic_cast_no_null_on_orig(OSObject *obj) {
327   OSArray *arr = OSDynamicCast(OSArray, obj);
328   if (arr) {
329     return arr->getCount();
330   } else {
331 
332     // The fact that dynamic cast has failed should not imply that
333     // the input object was null.
334     return obj->foo(); // no-warning
335   }
336 }
337 
338 void check_dynamic_cast_null_branch(OSObject *obj) {
339   OSArray *arr1 = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject}}
340   OSArray *arr = OSDynamicCast(OSArray, obj);
341   if (!arr) // expected-note{{Taking true branch}}
342     return; // expected-warning{{Potential leak of an object stored into 'arr1'}}
343             // expected-note@-1{{Object leaked}}
344   arr1->release();
345 }
346 
347 void check_dynamic_cast_null_check() {
348   OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); // expected-note{{Call to method 'OSObject::generateObject' returns an OSObject}}
349     // expected-warning@-1{{Potential leak of an object}}
350     // expected-note@-2{{Object leaked}}
351   if (!arr)
352     return;
353   arr->release();
354 }
355 
356 void use_after_release() {
357   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
358   arr->release(); // expected-note{{Object released}}
359   arr->getCount(); // expected-warning{{Reference-counted object is used after it is released}}
360                    // expected-note@-1{{Reference-counted object is used after it is released}}
361 }
362 
363 void potential_leak() {
364   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
365   arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
366   arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}}
367   arr->getCount();
368 } // expected-warning{{Potential leak of an object stored into 'arr'}}
369   // 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}}
370 
371 void proper_cleanup() {
372   OSArray *arr = OSArray::withCapacity(10); // +1
373   arr->retain(); // +2
374   arr->release(); // +1
375   arr->getCount();
376   arr->release(); // 0
377 }
378 
379 unsigned int no_warning_on_getter(ArrayOwner *owner) {
380   OSArray *arr = owner->getArray();
381   return arr->getCount();
382 }
383 
384 unsigned int warn_on_overrelease(ArrayOwner *owner) {
385   // FIXME: summaries are not applied in case the source of the getter/setter
386   // is known.
387   // rdar://45681203
388   OSArray *arr = owner->getArray();
389   arr->release();
390   return arr->getCount();
391 }
392 
393 unsigned int nowarn_on_release_of_created(ArrayOwner *owner) {
394   OSArray *arr = owner->createArray();
395   unsigned int out = arr->getCount();
396   arr->release();
397   return out;
398 }
399 
400 unsigned int nowarn_on_release_of_created_source_unknown(ArrayOwner *owner) {
401   OSArray *arr = owner->createArraySourceUnknown();
402   unsigned int out = arr->getCount();
403   arr->release();
404   return out;
405 }
406 
407 unsigned int no_warn_ok_release(ArrayOwner *owner) {
408   OSArray *arr = owner->getArray(); // +0
409   arr->retain(); // +1
410   arr->release(); // +0
411   return arr->getCount(); // no-warning
412 }
413 
414 unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) {
415   OSArray *arr = owner->getArraySourceUnknown(); // expected-note{{Call to method 'ArrayOwner::getArraySourceUnknown' returns an OSObject of type OSArray with a +0 retain count}}
416   arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
417                   // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
418   return arr->getCount();
419 }
420 
421 unsigned int ok_release_with_unknown_source(ArrayOwner *owner) {
422   OSArray *arr = owner->getArraySourceUnknown(); // +0
423   arr->retain(); // +1
424   arr->release(); // +0
425   return arr->getCount();
426 }
427 
428 OSObject *getObject();
429 typedef bool (^Blk)(OSObject *);
430 
431 void test_escape_to_unknown_block(Blk blk) {
432   blk(getObject()); // no-crash
433 }
434 
435