blob: 1b54008e4bda491886a9ebccaeee1925bbf8b564 [file] [log] [blame]
George Karpenkov57ef3a02018-10-31 17:38:12 +00001// RUN: %clang_analyze_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-output=text -verify %s
George Karpenkovab0011e2018-08-23 00:26:59 +00002
George Karpenkov41dc8de2018-10-11 22:59:16 +00003struct OSMetaClass;
4
George Karpenkovb43772d2018-11-30 02:18:50 +00005#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))
George Karpenkov081c4772018-10-23 23:11:50 +00008
George Karpenkov41dc8de2018-10-11 22:59:16 +00009#define OSTypeID(type) (type::metaClass)
10
11#define OSDynamicCast(type, inst) \
12 ((type *) OSMetaClassBase::safeMetaCast((inst), OSTypeID(type)))
13
George Karpenkovbe3f4bd2018-11-30 20:43:42 +000014using size_t = decltype(sizeof(int));
15
George Karpenkovab0011e2018-08-23 00:26:59 +000016struct OSObject {
17 virtual void retain();
George Karpenkov48de5822018-10-23 23:11:30 +000018 virtual void release() {};
George Karpenkovbe3f4bd2018-11-30 20:43:42 +000019 virtual void free();
George Karpenkovab0011e2018-08-23 00:26:59 +000020 virtual ~OSObject(){}
George Karpenkov41dc8de2018-10-11 22:59:16 +000021
George Karpenkov3c2ed8f2018-10-25 23:38:07 +000022 unsigned int foo() { return 42; }
23
George Karpenkov41dc8de2018-10-11 22:59:16 +000024 static OSObject *generateObject(int);
25
George Karpenkov3bdbeb12018-11-30 02:18:10 +000026 static OSObject *getObject();
27 static OSObject *GetObject();
28
George Karpenkovbe3f4bd2018-11-30 20:43:42 +000029
30 static void * operator new(size_t size);
31
George Karpenkov41dc8de2018-10-11 22:59:16 +000032 static const OSMetaClass * const metaClass;
George Karpenkovab0011e2018-08-23 00:26:59 +000033};
34
George Karpenkov83fb5362018-10-31 17:38:46 +000035struct OSIterator : public OSObject {
George Karpenkova1c3bb82018-11-30 02:17:31 +000036
37 static const OSMetaClass * const metaClass;
George Karpenkov83fb5362018-10-31 17:38:46 +000038};
39
George Karpenkovab0011e2018-08-23 00:26:59 +000040struct OSArray : public OSObject {
41 unsigned int getCount();
42
George Karpenkov62db8862018-11-30 02:18:23 +000043 static OSArray *generateArrayHasCode() {
44 return new OSArray;
45 }
46
George Karpenkovab0011e2018-08-23 00:26:59 +000047 static OSArray *withCapacity(unsigned int capacity);
George Karpenkov081c4772018-10-23 23:11:50 +000048 static void consumeArray(OS_CONSUME OSArray * array);
49
50 static OSArray* consumeArrayHasCode(OS_CONSUME OSArray * array) {
51 return nullptr;
52 }
53
George Karpenkov83fb5362018-10-31 17:38:46 +000054 OSIterator * getIterator();
55
George Karpenkov081c4772018-10-23 23:11:50 +000056 static OS_RETURNS_NOT_RETAINED OSArray *MaskedGetter();
57 static OS_RETURNS_RETAINED OSArray *getOoopsActuallyCreate();
58
George Karpenkov41dc8de2018-10-11 22:59:16 +000059 static const OSMetaClass * const metaClass;
George Karpenkovab0011e2018-08-23 00:26:59 +000060};
61
George Karpenkov081c4772018-10-23 23:11:50 +000062struct OtherStruct {
63 static void doNothingToArray(OSArray *array);
George Karpenkov3cfa04e2018-10-25 23:38:41 +000064 OtherStruct(OSArray *arr);
George Karpenkov081c4772018-10-23 23:11:50 +000065};
66
George Karpenkov41dc8de2018-10-11 22:59:16 +000067struct OSMetaClassBase {
68 static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta);
69};
70
George Karpenkovbe3f4bd2018-11-30 20:43:42 +000071void check_free_no_error() {
72 OSArray *arr = OSArray::withCapacity(10);
73 arr->retain();
74 arr->retain();
75 arr->retain();
76 arr->free();
77}
78
79void 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
87unsigned 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
93unsigned 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
George Karpenkov3bdbeb12018-11-30 02:18:10 +000099void check_get_object() {
100 OSObject::getObject();
101}
102
103void check_Get_object() {
104 OSObject::GetObject();
105}
106
George Karpenkov83fb5362018-10-31 17:38:46 +0000107void check_custom_iterator_rule(OSArray *arr) {
108 OSIterator *it = arr->getIterator();
109 it->release();
110}
111
George Karpenkove2f09542018-11-30 02:17:57 +0000112void check_iterator_leak(OSArray *arr) {
George Karpenkov62db8862018-11-30 02:18:23 +0000113 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}}
George Karpenkove2f09542018-11-30 02:17:57 +0000116
George Karpenkov081c4772018-10-23 23:11:50 +0000117void check_no_invalidation() {
George Karpenkove2f09542018-11-30 02:17:57 +0000118 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
George Karpenkov081c4772018-10-23 23:11:50 +0000119 OtherStruct::doNothingToArray(arr);
120} // expected-warning{{Potential leak of an object stored into 'arr'}}
121 // expected-note@-1{{Object leaked}}
122
George Karpenkov3cfa04e2018-10-25 23:38:41 +0000123void check_no_invalidation_other_struct() {
George Karpenkove2f09542018-11-30 02:17:57 +0000124 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
George Karpenkov3cfa04e2018-10-25 23:38:41 +0000125 OtherStruct other(arr); // expected-warning{{Potential leak}}
126 // expected-note@-1{{Object leaked}}
127}
128
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000129struct 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
George Karpenkova1c3bb82018-11-30 02:17:31 +0000150OSArray *generateArray() {
George Karpenkov62db8862018-11-30 02:18:23 +0000151 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}}
George Karpenkova1c3bb82018-11-30 02:17:31 +0000153}
154
155unsigned 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
166unsigned int check_leak_msg_temporary() {
George Karpenkovf893ea12018-11-30 02:17:44 +0000167 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}}
George Karpenkova1c3bb82018-11-30 02:17:31 +0000171}
172
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000173void 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
George Karpenkov081c4772018-10-23 23:11:50 +0000183void check_rc_consumed() {
184 OSArray *arr = OSArray::withCapacity(10);
185 OSArray::consumeArray(arr);
186}
187
188void check_rc_consume_temporary() {
189 OSArray::consumeArray(OSArray::withCapacity(10));
190}
191
192void check_rc_getter() {
193 OSArray *arr = OSArray::MaskedGetter();
194 (void)arr;
195}
196
197void check_rc_create() {
198 OSArray *arr = OSArray::getOoopsActuallyCreate();
199 arr->release();
200}
201
202
George Karpenkov41dc8de2018-10-11 22:59:16 +0000203void check_dynamic_cast() {
204 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1));
205 arr->release();
206}
207
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000208unsigned 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
220void check_dynamic_cast_null_branch(OSObject *obj) {
George Karpenkove2f09542018-11-30 02:17:57 +0000221 OSArray *arr1 = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000222 OSArray *arr = OSDynamicCast(OSArray, obj);
223 if (!arr) // expected-note{{Taking true branch}}
George Karpenkova1c3bb82018-11-30 02:17:31 +0000224 return; // expected-warning{{Potential leak of an object stored into 'arr1'}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000225 // expected-note@-1{{Object leaked}}
226 arr1->release();
227}
228
George Karpenkov41dc8de2018-10-11 22:59:16 +0000229void check_dynamic_cast_null_check() {
George Karpenkove2f09542018-11-30 02:17:57 +0000230 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); // expected-note{{Call to method 'OSObject::generateObject' returns an OSObject}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000231 // expected-warning@-1{{Potential leak of an object}}
232 // expected-note@-2{{Object leaked}}
George Karpenkov41dc8de2018-10-11 22:59:16 +0000233 if (!arr)
234 return;
235 arr->release();
236}
237
George Karpenkovab0011e2018-08-23 00:26:59 +0000238void use_after_release() {
George Karpenkov62db8862018-11-30 02:18:23 +0000239 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
George Karpenkovab0011e2018-08-23 00:26:59 +0000240 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
245void potential_leak() {
George Karpenkov62db8862018-11-30 02:18:23 +0000246 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
George Karpenkovab0011e2018-08-23 00:26:59 +0000247 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
253void 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
George Karpenkovab0011e2018-08-23 00:26:59 +0000261unsigned int no_warning_on_getter(ArrayOwner *owner) {
262 OSArray *arr = owner->getArray();
263 return arr->getCount();
264}
265
266unsigned int warn_on_overrelease(ArrayOwner *owner) {
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000267 // 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();
George Karpenkovab0011e2018-08-23 00:26:59 +0000272 return arr->getCount();
273}
274
275unsigned 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
282unsigned 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
289unsigned 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
296unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) {
George Karpenkove2f09542018-11-30 02:17:57 +0000297 OSArray *arr = owner->getArraySourceUnknown(); // expected-note{{Call to method 'ArrayOwner::getArraySourceUnknown' returns an OSObject of type OSArray with a +0 retain count}}
George Karpenkovab0011e2018-08-23 00:26:59 +0000298 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
303unsigned 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}