blob: 3720f04e059376b5474602a10c01d8fa3d331aef [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 Karpenkov6fd5c86d2018-10-31 17:38:29 +00005#define OS_CONSUME __attribute__((annotate("rc_ownership_consumed")))
6#define OS_RETURNS_RETAINED __attribute__((annotate("rc_ownership_returns_retained")))
7#define OS_RETURNS_NOT_RETAINED __attribute__((annotate("rc_ownership_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 Karpenkovab0011e2018-08-23 00:26:59 +000014struct OSObject {
15 virtual void retain();
George Karpenkov48de5822018-10-23 23:11:30 +000016 virtual void release() {};
George Karpenkovab0011e2018-08-23 00:26:59 +000017 virtual ~OSObject(){}
George Karpenkov41dc8de2018-10-11 22:59:16 +000018
George Karpenkov3c2ed8f2018-10-25 23:38:07 +000019 unsigned int foo() { return 42; }
20
George Karpenkov41dc8de2018-10-11 22:59:16 +000021 static OSObject *generateObject(int);
22
George Karpenkov3bdbeb12018-11-30 02:18:10 +000023 static OSObject *getObject();
24 static OSObject *GetObject();
25
George Karpenkov41dc8de2018-10-11 22:59:16 +000026 static const OSMetaClass * const metaClass;
George Karpenkovab0011e2018-08-23 00:26:59 +000027};
28
George Karpenkov83fb5362018-10-31 17:38:46 +000029struct OSIterator : public OSObject {
George Karpenkova1c3bb82018-11-30 02:17:31 +000030
31 static const OSMetaClass * const metaClass;
George Karpenkov83fb5362018-10-31 17:38:46 +000032};
33
George Karpenkovab0011e2018-08-23 00:26:59 +000034struct OSArray : public OSObject {
35 unsigned int getCount();
36
37 static OSArray *withCapacity(unsigned int capacity);
George Karpenkov081c4772018-10-23 23:11:50 +000038 static void consumeArray(OS_CONSUME OSArray * array);
39
40 static OSArray* consumeArrayHasCode(OS_CONSUME OSArray * array) {
41 return nullptr;
42 }
43
George Karpenkov83fb5362018-10-31 17:38:46 +000044 OSIterator * getIterator();
45
George Karpenkov081c4772018-10-23 23:11:50 +000046 static OS_RETURNS_NOT_RETAINED OSArray *MaskedGetter();
47 static OS_RETURNS_RETAINED OSArray *getOoopsActuallyCreate();
48
George Karpenkov41dc8de2018-10-11 22:59:16 +000049 static const OSMetaClass * const metaClass;
George Karpenkovab0011e2018-08-23 00:26:59 +000050};
51
George Karpenkov081c4772018-10-23 23:11:50 +000052struct OtherStruct {
53 static void doNothingToArray(OSArray *array);
George Karpenkov3cfa04e2018-10-25 23:38:41 +000054 OtherStruct(OSArray *arr);
George Karpenkov081c4772018-10-23 23:11:50 +000055};
56
George Karpenkov41dc8de2018-10-11 22:59:16 +000057struct OSMetaClassBase {
58 static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta);
59};
60
George Karpenkov3bdbeb12018-11-30 02:18:10 +000061void check_get_object() {
62 OSObject::getObject();
63}
64
65void check_Get_object() {
66 OSObject::GetObject();
67}
68
George Karpenkov83fb5362018-10-31 17:38:46 +000069void check_custom_iterator_rule(OSArray *arr) {
70 OSIterator *it = arr->getIterator();
71 it->release();
72}
73
George Karpenkove2f09542018-11-30 02:17:57 +000074void check_iterator_leak(OSArray *arr) {
75 arr->getIterator(); // expected-note{{Call to method 'OSArray::getIterator' returns an OSObject of type struct OSIterator * with a +1 retain count}}
76} // expected-note{{Object leaked: allocated object of type struct OSIterator * is not referenced later}}
77 // expected-warning@-1{{Potential leak of an object of type struct OSIterator *}}n this execution path and has a retain count of +1}}
78
George Karpenkov081c4772018-10-23 23:11:50 +000079void check_no_invalidation() {
George Karpenkove2f09542018-11-30 02:17:57 +000080 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 +000081 OtherStruct::doNothingToArray(arr);
82} // expected-warning{{Potential leak of an object stored into 'arr'}}
83 // expected-note@-1{{Object leaked}}
84
George Karpenkov3cfa04e2018-10-25 23:38:41 +000085void check_no_invalidation_other_struct() {
George Karpenkove2f09542018-11-30 02:17:57 +000086 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 +000087 OtherStruct other(arr); // expected-warning{{Potential leak}}
88 // expected-note@-1{{Object leaked}}
89}
90
George Karpenkov6fd5c86d2018-10-31 17:38:29 +000091struct ArrayOwner : public OSObject {
92 OSArray *arr;
93 ArrayOwner(OSArray *arr) : arr(arr) {}
94
95 static ArrayOwner* create(OSArray *arr) {
96 return new ArrayOwner(arr);
97 }
98
99 OSArray *getArray() {
100 return arr;
101 }
102
103 OSArray *createArray() {
104 return OSArray::withCapacity(10);
105 }
106
107 OSArray *createArraySourceUnknown();
108
109 OSArray *getArraySourceUnknown();
110};
111
George Karpenkova1c3bb82018-11-30 02:17:31 +0000112OSArray *generateArray() {
George Karpenkove2f09542018-11-30 02:17:57 +0000113 return OSArray::withCapacity(10); // expected-note{{Call to method 'withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
114 // expected-note@-1{{Call to method 'withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
George Karpenkova1c3bb82018-11-30 02:17:31 +0000115}
116
117unsigned int check_leak_good_error_message() {
118 unsigned int out;
119 {
120 OSArray *leaked = generateArray(); // expected-note{{Calling 'generateArray'}}
121 // expected-note@-1{{Returning from 'generateArray'}}
122 out = leaked->getCount(); // expected-warning{{Potential leak of an object stored into 'leaked'}}
123 // 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}}
124 }
125 return out;
126}
127
128unsigned int check_leak_msg_temporary() {
George Karpenkovf893ea12018-11-30 02:17:44 +0000129 return generateArray()->getCount(); // expected-warning{{Potential leak of an object}}
130 // expected-note@-1{{Calling 'generateArray'}}
131 // expected-note@-2{{Returning from 'generateArray'}}
132 // 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 +0000133}
134
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000135void check_confusing_getters() {
136 OSArray *arr = OSArray::withCapacity(10);
137
138 ArrayOwner *AO = ArrayOwner::create(arr);
139 AO->getArray();
140
141 AO->release();
142 arr->release();
143}
144
George Karpenkov081c4772018-10-23 23:11:50 +0000145void check_rc_consumed() {
146 OSArray *arr = OSArray::withCapacity(10);
147 OSArray::consumeArray(arr);
148}
149
150void check_rc_consume_temporary() {
151 OSArray::consumeArray(OSArray::withCapacity(10));
152}
153
154void check_rc_getter() {
155 OSArray *arr = OSArray::MaskedGetter();
156 (void)arr;
157}
158
159void check_rc_create() {
160 OSArray *arr = OSArray::getOoopsActuallyCreate();
161 arr->release();
162}
163
164
George Karpenkov41dc8de2018-10-11 22:59:16 +0000165void check_dynamic_cast() {
166 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1));
167 arr->release();
168}
169
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000170unsigned int check_dynamic_cast_no_null_on_orig(OSObject *obj) {
171 OSArray *arr = OSDynamicCast(OSArray, obj);
172 if (arr) {
173 return arr->getCount();
174 } else {
175
176 // The fact that dynamic cast has failed should not imply that
177 // the input object was null.
178 return obj->foo(); // no-warning
179 }
180}
181
182void check_dynamic_cast_null_branch(OSObject *obj) {
George Karpenkove2f09542018-11-30 02:17:57 +0000183 OSArray *arr1 = OSArray::withCapacity(10); // expected-note{{Call to method 'OSArray::withCapacity' returns an OSObject}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000184 OSArray *arr = OSDynamicCast(OSArray, obj);
185 if (!arr) // expected-note{{Taking true branch}}
George Karpenkova1c3bb82018-11-30 02:17:31 +0000186 return; // expected-warning{{Potential leak of an object stored into 'arr1'}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000187 // expected-note@-1{{Object leaked}}
188 arr1->release();
189}
190
George Karpenkov41dc8de2018-10-11 22:59:16 +0000191void check_dynamic_cast_null_check() {
George Karpenkove2f09542018-11-30 02:17:57 +0000192 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); // expected-note{{Call to method 'OSObject::generateObject' returns an OSObject}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000193 // expected-warning@-1{{Potential leak of an object}}
194 // expected-note@-2{{Object leaked}}
George Karpenkov41dc8de2018-10-11 22:59:16 +0000195 if (!arr)
196 return;
197 arr->release();
198}
199
George Karpenkovab0011e2018-08-23 00:26:59 +0000200void use_after_release() {
George Karpenkove2f09542018-11-30 02:17:57 +0000201 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
George Karpenkovab0011e2018-08-23 00:26:59 +0000202 arr->release(); // expected-note{{Object released}}
203 arr->getCount(); // expected-warning{{Reference-counted object is used after it is released}}
204 // expected-note@-1{{Reference-counted object is used after it is released}}
205}
206
207void potential_leak() {
George Karpenkove2f09542018-11-30 02:17:57 +0000208 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to method 'withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
George Karpenkovab0011e2018-08-23 00:26:59 +0000209 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
210 arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}}
211 arr->getCount();
212} // expected-warning{{Potential leak of an object stored into 'arr'}}
213 // 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}}
214
215void proper_cleanup() {
216 OSArray *arr = OSArray::withCapacity(10); // +1
217 arr->retain(); // +2
218 arr->release(); // +1
219 arr->getCount();
220 arr->release(); // 0
221}
222
George Karpenkovab0011e2018-08-23 00:26:59 +0000223unsigned int no_warning_on_getter(ArrayOwner *owner) {
224 OSArray *arr = owner->getArray();
225 return arr->getCount();
226}
227
228unsigned int warn_on_overrelease(ArrayOwner *owner) {
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000229 // FIXME: summaries are not applied in case the source of the getter/setter
230 // is known.
231 // rdar://45681203
232 OSArray *arr = owner->getArray();
233 arr->release();
George Karpenkovab0011e2018-08-23 00:26:59 +0000234 return arr->getCount();
235}
236
237unsigned int nowarn_on_release_of_created(ArrayOwner *owner) {
238 OSArray *arr = owner->createArray();
239 unsigned int out = arr->getCount();
240 arr->release();
241 return out;
242}
243
244unsigned int nowarn_on_release_of_created_source_unknown(ArrayOwner *owner) {
245 OSArray *arr = owner->createArraySourceUnknown();
246 unsigned int out = arr->getCount();
247 arr->release();
248 return out;
249}
250
251unsigned int no_warn_ok_release(ArrayOwner *owner) {
252 OSArray *arr = owner->getArray(); // +0
253 arr->retain(); // +1
254 arr->release(); // +0
255 return arr->getCount(); // no-warning
256}
257
258unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) {
George Karpenkove2f09542018-11-30 02:17:57 +0000259 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 +0000260 arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
261 // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
262 return arr->getCount();
263}
264
265unsigned int ok_release_with_unknown_source(ArrayOwner *owner) {
266 OSArray *arr = owner->getArraySourceUnknown(); // +0
267 arr->retain(); // +1
268 arr->release(); // +0
269 return arr->getCount();
270}