blob: 68529e9e972c09b1541fb3996dc6352e87cdf714 [file] [log] [blame]
George Karpenkov27db3302018-12-07 20:21:51 +00001// RUN: %clang_analyze_cc1 -analyze -analyzer-checker=core,osx -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 Karpenkovb0b61952018-12-06 22:07:12 +00008#define OS_CONSUMES_THIS __attribute__((os_consumes_this))
George Karpenkov081c4772018-10-23 23:11:50 +00009
George Karpenkov41dc8de2018-10-11 22:59:16 +000010#define OSTypeID(type) (type::metaClass)
11
12#define OSDynamicCast(type, inst) \
13 ((type *) OSMetaClassBase::safeMetaCast((inst), OSTypeID(type)))
14
George Karpenkovbe3f4bd2018-11-30 20:43:42 +000015using size_t = decltype(sizeof(int));
16
George Karpenkovab0011e2018-08-23 00:26:59 +000017struct OSObject {
18 virtual void retain();
George Karpenkov48de5822018-10-23 23:11:30 +000019 virtual void release() {};
George Karpenkovbe3f4bd2018-11-30 20:43:42 +000020 virtual void free();
George Karpenkovab0011e2018-08-23 00:26:59 +000021 virtual ~OSObject(){}
George Karpenkov41dc8de2018-10-11 22:59:16 +000022
George Karpenkov3c2ed8f2018-10-25 23:38:07 +000023 unsigned int foo() { return 42; }
24
George Karpenkova717bc72018-12-05 18:34:54 +000025 virtual OS_RETURNS_NOT_RETAINED OSObject *identity();
26
George Karpenkov41dc8de2018-10-11 22:59:16 +000027 static OSObject *generateObject(int);
28
George Karpenkov3bdbeb12018-11-30 02:18:10 +000029 static OSObject *getObject();
30 static OSObject *GetObject();
31
George Karpenkovbe3f4bd2018-11-30 20:43:42 +000032 static void * operator new(size_t size);
33
George Karpenkov41dc8de2018-10-11 22:59:16 +000034 static const OSMetaClass * const metaClass;
George Karpenkovab0011e2018-08-23 00:26:59 +000035};
36
George Karpenkov83fb5362018-10-31 17:38:46 +000037struct OSIterator : public OSObject {
George Karpenkova1c3bb82018-11-30 02:17:31 +000038
39 static const OSMetaClass * const metaClass;
George Karpenkov83fb5362018-10-31 17:38:46 +000040};
41
George Karpenkovab0011e2018-08-23 00:26:59 +000042struct OSArray : public OSObject {
43 unsigned int getCount();
44
George Karpenkova717bc72018-12-05 18:34:54 +000045 OSIterator * getIterator();
46
47 OSObject *identity() override;
48
George Karpenkova71ec6c2018-12-06 22:06:44 +000049 virtual OSObject *generateObject(OSObject *input);
50
George Karpenkova717bc72018-12-05 18:34:54 +000051 virtual void consumeReference(OS_CONSUME OSArray *other);
52
George Karpenkovb0b61952018-12-06 22:07:12 +000053 void putIntoArray(OSArray *array) OS_CONSUMES_THIS;
54
55 template <typename T>
56 void putIntoT(T *owner) OS_CONSUMES_THIS;
57
George Karpenkov62db8862018-11-30 02:18:23 +000058 static OSArray *generateArrayHasCode() {
59 return new OSArray;
60 }
61
George Karpenkovab0011e2018-08-23 00:26:59 +000062 static OSArray *withCapacity(unsigned int capacity);
George Karpenkov081c4772018-10-23 23:11:50 +000063 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
George Karpenkov41dc8de2018-10-11 22:59:16 +000072 static const OSMetaClass * const metaClass;
George Karpenkovab0011e2018-08-23 00:26:59 +000073};
74
George Karpenkova717bc72018-12-05 18:34:54 +000075struct MyArray : public OSArray {
76 void consumeReference(OSArray *other) override;
77
78 OSObject *identity() override;
George Karpenkova71ec6c2018-12-06 22:06:44 +000079
80 OSObject *generateObject(OSObject *input) override;
George Karpenkova717bc72018-12-05 18:34:54 +000081};
82
George Karpenkov081c4772018-10-23 23:11:50 +000083struct OtherStruct {
84 static void doNothingToArray(OSArray *array);
George Karpenkov3cfa04e2018-10-25 23:38:41 +000085 OtherStruct(OSArray *arr);
George Karpenkov081c4772018-10-23 23:11:50 +000086};
87
George Karpenkov41dc8de2018-10-11 22:59:16 +000088struct OSMetaClassBase {
89 static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta);
90};
91
George Karpenkov041c9fa2018-12-08 01:18:40 +000092void escape(void *);
93
94void test_escaping_into_voidstar() {
95 OSObject *obj = new OSObject;
96 escape(obj);
97}
98
George Karpenkova71ec6c2018-12-06 22:06:44 +000099void test_no_infinite_check_recursion(MyArray *arr) {
100 OSObject *input = new OSObject;
101 OSObject *o = arr->generateObject(input);
102 o->release();
103 input->release();
104}
105
106
George Karpenkova717bc72018-12-05 18:34:54 +0000107void check_param_attribute_propagation(MyArray *parent) {
108 OSArray *arr = new OSArray;
109 parent->consumeReference(arr);
110}
111
112unsigned int check_attribute_propagation(OSArray *arr) {
113 OSObject *other = arr->identity();
114 OSArray *casted = OSDynamicCast(OSArray, other);
115 if (casted)
116 return casted->getCount();
117 return 0;
118}
119
120unsigned int check_attribute_indirect_propagation(MyArray *arr) {
121 OSObject *other = arr->identity();
122 OSArray *casted = OSDynamicCast(OSArray, other);
123 if (casted)
124 return casted->getCount();
125 return 0;
126}
127
George Karpenkovb0b61952018-12-06 22:07:12 +0000128void check_consumes_this(OSArray *owner) {
129 OSArray *arr = new OSArray;
130 arr->putIntoArray(owner);
131}
132
133void check_consumes_this_with_template(OSArray *owner) {
134 OSArray *arr = new OSArray;
135 arr->putIntoT(owner);
136}
137
George Karpenkovbe3f4bd2018-11-30 20:43:42 +0000138void check_free_no_error() {
139 OSArray *arr = OSArray::withCapacity(10);
140 arr->retain();
141 arr->retain();
142 arr->retain();
143 arr->free();
144}
145
146void check_free_use_after_free() {
147 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
148 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
149 arr->free(); // expected-note{{Object released}}
150 arr->retain(); // expected-warning{{Reference-counted object is used after it is released}}
151 // expected-note@-1{{Reference-counted object is used after it is released}}
152}
153
154unsigned int check_leak_explicit_new() {
155 OSArray *arr = new OSArray; // expected-note{{Operator new returns an OSObject of type OSArray with a +1 retain count}}
156 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}}
157 // expected-warning@-1{{Potential leak of an object of type OSArray}}
158}
159
160unsigned int check_leak_factory() {
161 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
162 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}}
163 // expected-warning@-1{{Potential leak of an object stored into 'arr'}}
164}
165
George Karpenkov3bdbeb12018-11-30 02:18:10 +0000166void check_get_object() {
167 OSObject::getObject();
168}
169
170void check_Get_object() {
171 OSObject::GetObject();
172}
173
George Karpenkov83fb5362018-10-31 17:38:46 +0000174void check_custom_iterator_rule(OSArray *arr) {
175 OSIterator *it = arr->getIterator();
176 it->release();
177}
178
George Karpenkove2f09542018-11-30 02:17:57 +0000179void check_iterator_leak(OSArray *arr) {
George Karpenkov62db8862018-11-30 02:18:23 +0000180 arr->getIterator(); // expected-note{{Call to method 'OSArray::getIterator' returns an OSObject of type OSIterator with a +1 retain count}}
181} // expected-note{{Object leaked: allocated object of type OSIterator is not referenced later}}
182 // expected-warning@-1{{Potential leak of an object of type OSIterator}}
George Karpenkove2f09542018-11-30 02:17:57 +0000183
George Karpenkov081c4772018-10-23 23:11:50 +0000184void check_no_invalidation() {
George Karpenkove2f09542018-11-30 02:17:57 +0000185 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 +0000186 OtherStruct::doNothingToArray(arr);
187} // expected-warning{{Potential leak of an object stored into 'arr'}}
188 // expected-note@-1{{Object leaked}}
189
George Karpenkov3cfa04e2018-10-25 23:38:41 +0000190void check_no_invalidation_other_struct() {
George Karpenkove2f09542018-11-30 02:17:57 +0000191 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 +0000192 OtherStruct other(arr); // expected-warning{{Potential leak}}
193 // expected-note@-1{{Object leaked}}
194}
195
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000196struct ArrayOwner : public OSObject {
197 OSArray *arr;
198 ArrayOwner(OSArray *arr) : arr(arr) {}
199
200 static ArrayOwner* create(OSArray *arr) {
201 return new ArrayOwner(arr);
202 }
203
204 OSArray *getArray() {
205 return arr;
206 }
207
208 OSArray *createArray() {
209 return OSArray::withCapacity(10);
210 }
211
212 OSArray *createArraySourceUnknown();
213
214 OSArray *getArraySourceUnknown();
215};
216
George Karpenkova1c3bb82018-11-30 02:17:31 +0000217OSArray *generateArray() {
George Karpenkov62db8862018-11-30 02:18:23 +0000218 return OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
219 // 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 +0000220}
221
222unsigned int check_leak_good_error_message() {
223 unsigned int out;
224 {
225 OSArray *leaked = generateArray(); // expected-note{{Calling 'generateArray'}}
226 // expected-note@-1{{Returning from 'generateArray'}}
227 out = leaked->getCount(); // expected-warning{{Potential leak of an object stored into 'leaked'}}
228 // 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}}
229 }
230 return out;
231}
232
233unsigned int check_leak_msg_temporary() {
George Karpenkovf893ea12018-11-30 02:17:44 +0000234 return generateArray()->getCount(); // expected-warning{{Potential leak of an object}}
235 // expected-note@-1{{Calling 'generateArray'}}
236 // expected-note@-2{{Returning from 'generateArray'}}
237 // 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 +0000238}
239
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000240void check_confusing_getters() {
241 OSArray *arr = OSArray::withCapacity(10);
242
243 ArrayOwner *AO = ArrayOwner::create(arr);
244 AO->getArray();
245
246 AO->release();
247 arr->release();
248}
249
George Karpenkov081c4772018-10-23 23:11:50 +0000250void check_rc_consumed() {
251 OSArray *arr = OSArray::withCapacity(10);
252 OSArray::consumeArray(arr);
253}
254
255void check_rc_consume_temporary() {
256 OSArray::consumeArray(OSArray::withCapacity(10));
257}
258
259void check_rc_getter() {
260 OSArray *arr = OSArray::MaskedGetter();
261 (void)arr;
262}
263
264void check_rc_create() {
265 OSArray *arr = OSArray::getOoopsActuallyCreate();
266 arr->release();
267}
268
269
George Karpenkov41dc8de2018-10-11 22:59:16 +0000270void check_dynamic_cast() {
271 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1));
272 arr->release();
273}
274
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000275unsigned int check_dynamic_cast_no_null_on_orig(OSObject *obj) {
276 OSArray *arr = OSDynamicCast(OSArray, obj);
277 if (arr) {
278 return arr->getCount();
279 } else {
280
281 // The fact that dynamic cast has failed should not imply that
282 // the input object was null.
283 return obj->foo(); // no-warning
284 }
285}
286
287void check_dynamic_cast_null_branch(OSObject *obj) {
George Karpenkove2f09542018-11-30 02:17:57 +0000288 OSArray *arr1 = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000289 OSArray *arr = OSDynamicCast(OSArray, obj);
290 if (!arr) // expected-note{{Taking true branch}}
George Karpenkova1c3bb82018-11-30 02:17:31 +0000291 return; // expected-warning{{Potential leak of an object stored into 'arr1'}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000292 // expected-note@-1{{Object leaked}}
293 arr1->release();
294}
295
George Karpenkov41dc8de2018-10-11 22:59:16 +0000296void check_dynamic_cast_null_check() {
George Karpenkove2f09542018-11-30 02:17:57 +0000297 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); // expected-note{{Call to method 'OSObject::generateObject' returns an OSObject}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000298 // expected-warning@-1{{Potential leak of an object}}
299 // expected-note@-2{{Object leaked}}
George Karpenkov41dc8de2018-10-11 22:59:16 +0000300 if (!arr)
301 return;
302 arr->release();
303}
304
George Karpenkovab0011e2018-08-23 00:26:59 +0000305void use_after_release() {
George Karpenkov62db8862018-11-30 02:18:23 +0000306 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 +0000307 arr->release(); // expected-note{{Object released}}
308 arr->getCount(); // expected-warning{{Reference-counted object is used after it is released}}
309 // expected-note@-1{{Reference-counted object is used after it is released}}
310}
311
312void potential_leak() {
George Karpenkov62db8862018-11-30 02:18:23 +0000313 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 +0000314 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
315 arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}}
316 arr->getCount();
317} // expected-warning{{Potential leak of an object stored into 'arr'}}
318 // 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}}
319
320void proper_cleanup() {
321 OSArray *arr = OSArray::withCapacity(10); // +1
322 arr->retain(); // +2
323 arr->release(); // +1
324 arr->getCount();
325 arr->release(); // 0
326}
327
George Karpenkovab0011e2018-08-23 00:26:59 +0000328unsigned int no_warning_on_getter(ArrayOwner *owner) {
329 OSArray *arr = owner->getArray();
330 return arr->getCount();
331}
332
333unsigned int warn_on_overrelease(ArrayOwner *owner) {
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000334 // FIXME: summaries are not applied in case the source of the getter/setter
335 // is known.
336 // rdar://45681203
337 OSArray *arr = owner->getArray();
338 arr->release();
George Karpenkovab0011e2018-08-23 00:26:59 +0000339 return arr->getCount();
340}
341
342unsigned int nowarn_on_release_of_created(ArrayOwner *owner) {
343 OSArray *arr = owner->createArray();
344 unsigned int out = arr->getCount();
345 arr->release();
346 return out;
347}
348
349unsigned int nowarn_on_release_of_created_source_unknown(ArrayOwner *owner) {
350 OSArray *arr = owner->createArraySourceUnknown();
351 unsigned int out = arr->getCount();
352 arr->release();
353 return out;
354}
355
356unsigned int no_warn_ok_release(ArrayOwner *owner) {
357 OSArray *arr = owner->getArray(); // +0
358 arr->retain(); // +1
359 arr->release(); // +0
360 return arr->getCount(); // no-warning
361}
362
363unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) {
George Karpenkove2f09542018-11-30 02:17:57 +0000364 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 +0000365 arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
366 // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
367 return arr->getCount();
368}
369
370unsigned int ok_release_with_unknown_source(ArrayOwner *owner) {
371 OSArray *arr = owner->getArraySourceUnknown(); // +0
372 arr->retain(); // +1
373 arr->release(); // +0
374 return arr->getCount();
375}