blob: 9c8bd78726a4280d912bc9a83dfe1a3b14355564 [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 Karpenkova71ec6c2018-12-06 22:06:44 +000092void test_no_infinite_check_recursion(MyArray *arr) {
93 OSObject *input = new OSObject;
94 OSObject *o = arr->generateObject(input);
95 o->release();
96 input->release();
97}
98
99
George Karpenkova717bc72018-12-05 18:34:54 +0000100void check_param_attribute_propagation(MyArray *parent) {
101 OSArray *arr = new OSArray;
102 parent->consumeReference(arr);
103}
104
105unsigned int check_attribute_propagation(OSArray *arr) {
106 OSObject *other = arr->identity();
107 OSArray *casted = OSDynamicCast(OSArray, other);
108 if (casted)
109 return casted->getCount();
110 return 0;
111}
112
113unsigned int check_attribute_indirect_propagation(MyArray *arr) {
114 OSObject *other = arr->identity();
115 OSArray *casted = OSDynamicCast(OSArray, other);
116 if (casted)
117 return casted->getCount();
118 return 0;
119}
120
George Karpenkovb0b61952018-12-06 22:07:12 +0000121void check_consumes_this(OSArray *owner) {
122 OSArray *arr = new OSArray;
123 arr->putIntoArray(owner);
124}
125
126void check_consumes_this_with_template(OSArray *owner) {
127 OSArray *arr = new OSArray;
128 arr->putIntoT(owner);
129}
130
George Karpenkovbe3f4bd2018-11-30 20:43:42 +0000131void check_free_no_error() {
132 OSArray *arr = OSArray::withCapacity(10);
133 arr->retain();
134 arr->retain();
135 arr->retain();
136 arr->free();
137}
138
139void check_free_use_after_free() {
140 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
141 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
142 arr->free(); // expected-note{{Object released}}
143 arr->retain(); // expected-warning{{Reference-counted object is used after it is released}}
144 // expected-note@-1{{Reference-counted object is used after it is released}}
145}
146
147unsigned int check_leak_explicit_new() {
148 OSArray *arr = new OSArray; // expected-note{{Operator new returns an OSObject of type OSArray with a +1 retain count}}
149 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}}
150 // expected-warning@-1{{Potential leak of an object of type OSArray}}
151}
152
153unsigned int check_leak_factory() {
154 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
155 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}}
156 // expected-warning@-1{{Potential leak of an object stored into 'arr'}}
157}
158
George Karpenkov3bdbeb12018-11-30 02:18:10 +0000159void check_get_object() {
160 OSObject::getObject();
161}
162
163void check_Get_object() {
164 OSObject::GetObject();
165}
166
George Karpenkov83fb5362018-10-31 17:38:46 +0000167void check_custom_iterator_rule(OSArray *arr) {
168 OSIterator *it = arr->getIterator();
169 it->release();
170}
171
George Karpenkove2f09542018-11-30 02:17:57 +0000172void check_iterator_leak(OSArray *arr) {
George Karpenkov62db8862018-11-30 02:18:23 +0000173 arr->getIterator(); // expected-note{{Call to method 'OSArray::getIterator' returns an OSObject of type OSIterator with a +1 retain count}}
174} // expected-note{{Object leaked: allocated object of type OSIterator is not referenced later}}
175 // expected-warning@-1{{Potential leak of an object of type OSIterator}}
George Karpenkove2f09542018-11-30 02:17:57 +0000176
George Karpenkov081c4772018-10-23 23:11:50 +0000177void check_no_invalidation() {
George Karpenkove2f09542018-11-30 02:17:57 +0000178 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 +0000179 OtherStruct::doNothingToArray(arr);
180} // expected-warning{{Potential leak of an object stored into 'arr'}}
181 // expected-note@-1{{Object leaked}}
182
George Karpenkov3cfa04e2018-10-25 23:38:41 +0000183void check_no_invalidation_other_struct() {
George Karpenkove2f09542018-11-30 02:17:57 +0000184 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 +0000185 OtherStruct other(arr); // expected-warning{{Potential leak}}
186 // expected-note@-1{{Object leaked}}
187}
188
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000189struct ArrayOwner : public OSObject {
190 OSArray *arr;
191 ArrayOwner(OSArray *arr) : arr(arr) {}
192
193 static ArrayOwner* create(OSArray *arr) {
194 return new ArrayOwner(arr);
195 }
196
197 OSArray *getArray() {
198 return arr;
199 }
200
201 OSArray *createArray() {
202 return OSArray::withCapacity(10);
203 }
204
205 OSArray *createArraySourceUnknown();
206
207 OSArray *getArraySourceUnknown();
208};
209
George Karpenkova1c3bb82018-11-30 02:17:31 +0000210OSArray *generateArray() {
George Karpenkov62db8862018-11-30 02:18:23 +0000211 return OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
212 // 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 +0000213}
214
215unsigned int check_leak_good_error_message() {
216 unsigned int out;
217 {
218 OSArray *leaked = generateArray(); // expected-note{{Calling 'generateArray'}}
219 // expected-note@-1{{Returning from 'generateArray'}}
220 out = leaked->getCount(); // expected-warning{{Potential leak of an object stored into 'leaked'}}
221 // 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}}
222 }
223 return out;
224}
225
226unsigned int check_leak_msg_temporary() {
George Karpenkovf893ea12018-11-30 02:17:44 +0000227 return generateArray()->getCount(); // expected-warning{{Potential leak of an object}}
228 // expected-note@-1{{Calling 'generateArray'}}
229 // expected-note@-2{{Returning from 'generateArray'}}
230 // 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 +0000231}
232
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000233void check_confusing_getters() {
234 OSArray *arr = OSArray::withCapacity(10);
235
236 ArrayOwner *AO = ArrayOwner::create(arr);
237 AO->getArray();
238
239 AO->release();
240 arr->release();
241}
242
George Karpenkov081c4772018-10-23 23:11:50 +0000243void check_rc_consumed() {
244 OSArray *arr = OSArray::withCapacity(10);
245 OSArray::consumeArray(arr);
246}
247
248void check_rc_consume_temporary() {
249 OSArray::consumeArray(OSArray::withCapacity(10));
250}
251
252void check_rc_getter() {
253 OSArray *arr = OSArray::MaskedGetter();
254 (void)arr;
255}
256
257void check_rc_create() {
258 OSArray *arr = OSArray::getOoopsActuallyCreate();
259 arr->release();
260}
261
262
George Karpenkov41dc8de2018-10-11 22:59:16 +0000263void check_dynamic_cast() {
264 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1));
265 arr->release();
266}
267
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000268unsigned int check_dynamic_cast_no_null_on_orig(OSObject *obj) {
269 OSArray *arr = OSDynamicCast(OSArray, obj);
270 if (arr) {
271 return arr->getCount();
272 } else {
273
274 // The fact that dynamic cast has failed should not imply that
275 // the input object was null.
276 return obj->foo(); // no-warning
277 }
278}
279
280void check_dynamic_cast_null_branch(OSObject *obj) {
George Karpenkove2f09542018-11-30 02:17:57 +0000281 OSArray *arr1 = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000282 OSArray *arr = OSDynamicCast(OSArray, obj);
283 if (!arr) // expected-note{{Taking true branch}}
George Karpenkova1c3bb82018-11-30 02:17:31 +0000284 return; // expected-warning{{Potential leak of an object stored into 'arr1'}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000285 // expected-note@-1{{Object leaked}}
286 arr1->release();
287}
288
George Karpenkov41dc8de2018-10-11 22:59:16 +0000289void check_dynamic_cast_null_check() {
George Karpenkove2f09542018-11-30 02:17:57 +0000290 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); // expected-note{{Call to method 'OSObject::generateObject' returns an OSObject}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000291 // expected-warning@-1{{Potential leak of an object}}
292 // expected-note@-2{{Object leaked}}
George Karpenkov41dc8de2018-10-11 22:59:16 +0000293 if (!arr)
294 return;
295 arr->release();
296}
297
George Karpenkovab0011e2018-08-23 00:26:59 +0000298void use_after_release() {
George Karpenkov62db8862018-11-30 02:18:23 +0000299 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 +0000300 arr->release(); // expected-note{{Object released}}
301 arr->getCount(); // expected-warning{{Reference-counted object is used after it is released}}
302 // expected-note@-1{{Reference-counted object is used after it is released}}
303}
304
305void potential_leak() {
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->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
308 arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}}
309 arr->getCount();
310} // expected-warning{{Potential leak of an object stored into 'arr'}}
311 // 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}}
312
313void proper_cleanup() {
314 OSArray *arr = OSArray::withCapacity(10); // +1
315 arr->retain(); // +2
316 arr->release(); // +1
317 arr->getCount();
318 arr->release(); // 0
319}
320
George Karpenkovab0011e2018-08-23 00:26:59 +0000321unsigned int no_warning_on_getter(ArrayOwner *owner) {
322 OSArray *arr = owner->getArray();
323 return arr->getCount();
324}
325
326unsigned int warn_on_overrelease(ArrayOwner *owner) {
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000327 // FIXME: summaries are not applied in case the source of the getter/setter
328 // is known.
329 // rdar://45681203
330 OSArray *arr = owner->getArray();
331 arr->release();
George Karpenkovab0011e2018-08-23 00:26:59 +0000332 return arr->getCount();
333}
334
335unsigned int nowarn_on_release_of_created(ArrayOwner *owner) {
336 OSArray *arr = owner->createArray();
337 unsigned int out = arr->getCount();
338 arr->release();
339 return out;
340}
341
342unsigned int nowarn_on_release_of_created_source_unknown(ArrayOwner *owner) {
343 OSArray *arr = owner->createArraySourceUnknown();
344 unsigned int out = arr->getCount();
345 arr->release();
346 return out;
347}
348
349unsigned int no_warn_ok_release(ArrayOwner *owner) {
350 OSArray *arr = owner->getArray(); // +0
351 arr->retain(); // +1
352 arr->release(); // +0
353 return arr->getCount(); // no-warning
354}
355
356unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) {
George Karpenkove2f09542018-11-30 02:17:57 +0000357 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 +0000358 arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
359 // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
360 return arr->getCount();
361}
362
363unsigned int ok_release_with_unknown_source(ArrayOwner *owner) {
364 OSArray *arr = owner->getArraySourceUnknown(); // +0
365 arr->retain(); // +1
366 arr->release(); // +0
367 return arr->getCount();
368}