1 // RUN: %clang_analyze_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -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 
9 #define OSTypeID(type)   (type::metaClass)
10 
11 #define OSDynamicCast(type, inst)   \
12     ((type *) OSMetaClassBase::safeMetaCast((inst), OSTypeID(type)))
13 
14 using size_t = decltype(sizeof(int));
15 
16 struct OSObject {
17   virtual void retain();
18   virtual void release() {};
19   virtual void free();
20   virtual ~OSObject(){}
21 
22   unsigned int foo() { return 42; }
23 
24   static OSObject *generateObject(int);
25 
26   static OSObject *getObject();
27   static OSObject *GetObject();
28 
29 
30   static void * operator new(size_t size);
31 
32   static const OSMetaClass * const metaClass;
33 };
34 
35 struct OSIterator : public OSObject {
36 
37   static const OSMetaClass * const metaClass;
38 };
39 
40 struct OSArray : public OSObject {
41   unsigned int getCount();
42 
43   static OSArray *generateArrayHasCode() {
44     return new OSArray;
45   }
46 
47   static OSArray *withCapacity(unsigned int capacity);
48   static void consumeArray(OS_CONSUME OSArray * array);
49 
50   static OSArray* consumeArrayHasCode(OS_CONSUME OSArray * array) {
51     return nullptr;
52   }
53 
54   OSIterator * getIterator();
55 
56   static OS_RETURNS_NOT_RETAINED OSArray *MaskedGetter();
57   static OS_RETURNS_RETAINED OSArray *getOoopsActuallyCreate();
58 
59   static const OSMetaClass * const metaClass;
60 };
61 
62 struct OtherStruct {
63   static void doNothingToArray(OSArray *array);
64   OtherStruct(OSArray *arr);
65 };
66 
67 struct OSMetaClassBase {
68   static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta);
69 };
70 
71 void check_free_no_error() {
72   OSArray *arr = OSArray::withCapacity(10);
73   arr->retain();
74   arr->retain();
75   arr->retain();
76   arr->free();
77 }
78 
79 void check_free_use_after_free() {
80   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
81   arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
82   arr->free(); // expected-note{{Object released}}
83   arr->retain(); // expected-warning{{Reference-counted object is used after it is released}}
84                  // expected-note@-1{{Reference-counted object is used after it is released}}
85 }
86 
87 unsigned int check_leak_explicit_new() {
88   OSArray *arr = new OSArray; // expected-note{{Operator new returns an OSObject of type OSArray with a +1 retain count}}
89   return arr->getCount(); // expected-note{{Object leaked: allocated object of type OSArray is not referenced later in this execution path and has a retain count of +1}}
90                           // expected-warning@-1{{Potential leak of an object of type OSArray}}
91 }
92 
93 unsigned int check_leak_factory() {
94   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
95   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}}
96                           // expected-warning@-1{{Potential leak of an object stored into 'arr'}}
97 }
98 
99 void check_get_object() {
100   OSObject::getObject();
101 }
102 
103 void check_Get_object() {
104   OSObject::GetObject();
105 }
106 
107 void check_custom_iterator_rule(OSArray *arr) {
108   OSIterator *it = arr->getIterator();
109   it->release();
110 }
111 
112 void check_iterator_leak(OSArray *arr) {
113   arr->getIterator(); // expected-note{{Call to method 'OSArray::getIterator' returns an OSObject of type OSIterator with a +1 retain count}}
114 } // expected-note{{Object leaked: allocated object of type OSIterator is not referenced later}}
115   // expected-warning@-1{{Potential leak of an object of type OSIterator}}
116 
117 void check_no_invalidation() {
118   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
119   OtherStruct::doNothingToArray(arr);
120 } // expected-warning{{Potential leak of an object stored into 'arr'}}
121   // expected-note@-1{{Object leaked}}
122 
123 void check_no_invalidation_other_struct() {
124   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
125   OtherStruct other(arr); // expected-warning{{Potential leak}}
126                           // expected-note@-1{{Object leaked}}
127 }
128 
129 struct ArrayOwner : public OSObject {
130   OSArray *arr;
131   ArrayOwner(OSArray *arr) : arr(arr) {}
132 
133   static ArrayOwner* create(OSArray *arr) {
134     return new ArrayOwner(arr);
135   }
136 
137   OSArray *getArray() {
138     return arr;
139   }
140 
141   OSArray *createArray() {
142     return OSArray::withCapacity(10);
143   }
144 
145   OSArray *createArraySourceUnknown();
146 
147   OSArray *getArraySourceUnknown();
148 };
149 
150 OSArray *generateArray() {
151   return OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
152                                     // expected-note@-1{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
153 }
154 
155 unsigned int check_leak_good_error_message() {
156   unsigned int out;
157   {
158     OSArray *leaked = generateArray(); // expected-note{{Calling 'generateArray'}}
159                                        // expected-note@-1{{Returning from 'generateArray'}}
160     out = leaked->getCount(); // expected-warning{{Potential leak of an object stored into 'leaked'}}
161                               // 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}}
162   }
163   return out;
164 }
165 
166 unsigned int check_leak_msg_temporary() {
167   return generateArray()->getCount(); // expected-warning{{Potential leak of an object}}
168                                       // expected-note@-1{{Calling 'generateArray'}}
169                                       // expected-note@-2{{Returning from 'generateArray'}}
170                                       // 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}}
171 }
172 
173 void check_confusing_getters() {
174   OSArray *arr = OSArray::withCapacity(10);
175 
176   ArrayOwner *AO = ArrayOwner::create(arr);
177   AO->getArray();
178 
179   AO->release();
180   arr->release();
181 }
182 
183 void check_rc_consumed() {
184   OSArray *arr = OSArray::withCapacity(10);
185   OSArray::consumeArray(arr);
186 }
187 
188 void check_rc_consume_temporary() {
189   OSArray::consumeArray(OSArray::withCapacity(10));
190 }
191 
192 void check_rc_getter() {
193   OSArray *arr = OSArray::MaskedGetter();
194   (void)arr;
195 }
196 
197 void check_rc_create() {
198   OSArray *arr = OSArray::getOoopsActuallyCreate();
199   arr->release();
200 }
201 
202 
203 void check_dynamic_cast() {
204   OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1));
205   arr->release();
206 }
207 
208 unsigned int check_dynamic_cast_no_null_on_orig(OSObject *obj) {
209   OSArray *arr = OSDynamicCast(OSArray, obj);
210   if (arr) {
211     return arr->getCount();
212   } else {
213 
214     // The fact that dynamic cast has failed should not imply that
215     // the input object was null.
216     return obj->foo(); // no-warning
217   }
218 }
219 
220 void check_dynamic_cast_null_branch(OSObject *obj) {
221   OSArray *arr1 = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject}}
222   OSArray *arr = OSDynamicCast(OSArray, obj);
223   if (!arr) // expected-note{{Taking true branch}}
224     return; // expected-warning{{Potential leak of an object stored into 'arr1'}}
225             // expected-note@-1{{Object leaked}}
226   arr1->release();
227 }
228 
229 void check_dynamic_cast_null_check() {
230   OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); // expected-note{{Call to method 'OSObject::generateObject' returns an OSObject}}
231     // expected-warning@-1{{Potential leak of an object}}
232     // expected-note@-2{{Object leaked}}
233   if (!arr)
234     return;
235   arr->release();
236 }
237 
238 void use_after_release() {
239   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
240   arr->release(); // expected-note{{Object released}}
241   arr->getCount(); // expected-warning{{Reference-counted object is used after it is released}}
242                    // expected-note@-1{{Reference-counted object is used after it is released}}
243 }
244 
245 void potential_leak() {
246   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
247   arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
248   arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}}
249   arr->getCount();
250 } // expected-warning{{Potential leak of an object stored into 'arr'}}
251   // 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}}
252 
253 void proper_cleanup() {
254   OSArray *arr = OSArray::withCapacity(10); // +1
255   arr->retain(); // +2
256   arr->release(); // +1
257   arr->getCount();
258   arr->release(); // 0
259 }
260 
261 unsigned int no_warning_on_getter(ArrayOwner *owner) {
262   OSArray *arr = owner->getArray();
263   return arr->getCount();
264 }
265 
266 unsigned int warn_on_overrelease(ArrayOwner *owner) {
267   // FIXME: summaries are not applied in case the source of the getter/setter
268   // is known.
269   // rdar://45681203
270   OSArray *arr = owner->getArray();
271   arr->release();
272   return arr->getCount();
273 }
274 
275 unsigned int nowarn_on_release_of_created(ArrayOwner *owner) {
276   OSArray *arr = owner->createArray();
277   unsigned int out = arr->getCount();
278   arr->release();
279   return out;
280 }
281 
282 unsigned int nowarn_on_release_of_created_source_unknown(ArrayOwner *owner) {
283   OSArray *arr = owner->createArraySourceUnknown();
284   unsigned int out = arr->getCount();
285   arr->release();
286   return out;
287 }
288 
289 unsigned int no_warn_ok_release(ArrayOwner *owner) {
290   OSArray *arr = owner->getArray(); // +0
291   arr->retain(); // +1
292   arr->release(); // +0
293   return arr->getCount(); // no-warning
294 }
295 
296 unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) {
297   OSArray *arr = owner->getArraySourceUnknown(); // expected-note{{Call to method 'ArrayOwner::getArraySourceUnknown' returns an OSObject of type OSArray with a +0 retain count}}
298   arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
299                   // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
300   return arr->getCount();
301 }
302 
303 unsigned int ok_release_with_unknown_source(ArrayOwner *owner) {
304   OSArray *arr = owner->getArraySourceUnknown(); // +0
305   arr->retain(); // +1
306   arr->release(); // +0
307   return arr->getCount();
308 }
309