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