blob: d53ebbab5f098cf608f92c380f41e05216189bf3 [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
23 static const OSMetaClass * const metaClass;
George Karpenkovab0011e2018-08-23 00:26:59 +000024};
25
George Karpenkov83fb5362018-10-31 17:38:46 +000026struct OSIterator : public OSObject {
George Karpenkova1c3bb82018-11-30 02:17:31 +000027
28 static const OSMetaClass * const metaClass;
George Karpenkov83fb5362018-10-31 17:38:46 +000029};
30
George Karpenkovab0011e2018-08-23 00:26:59 +000031struct OSArray : public OSObject {
32 unsigned int getCount();
33
34 static OSArray *withCapacity(unsigned int capacity);
George Karpenkov081c4772018-10-23 23:11:50 +000035 static void consumeArray(OS_CONSUME OSArray * array);
36
37 static OSArray* consumeArrayHasCode(OS_CONSUME OSArray * array) {
38 return nullptr;
39 }
40
George Karpenkov83fb5362018-10-31 17:38:46 +000041 OSIterator * getIterator();
42
George Karpenkov081c4772018-10-23 23:11:50 +000043 static OS_RETURNS_NOT_RETAINED OSArray *MaskedGetter();
44 static OS_RETURNS_RETAINED OSArray *getOoopsActuallyCreate();
45
George Karpenkov41dc8de2018-10-11 22:59:16 +000046 static const OSMetaClass * const metaClass;
George Karpenkovab0011e2018-08-23 00:26:59 +000047};
48
George Karpenkov081c4772018-10-23 23:11:50 +000049struct OtherStruct {
50 static void doNothingToArray(OSArray *array);
George Karpenkov3cfa04e2018-10-25 23:38:41 +000051 OtherStruct(OSArray *arr);
George Karpenkov081c4772018-10-23 23:11:50 +000052};
53
George Karpenkov41dc8de2018-10-11 22:59:16 +000054struct OSMetaClassBase {
55 static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta);
56};
57
George Karpenkov83fb5362018-10-31 17:38:46 +000058void check_custom_iterator_rule(OSArray *arr) {
59 OSIterator *it = arr->getIterator();
60 it->release();
61}
62
George Karpenkov081c4772018-10-23 23:11:50 +000063void check_no_invalidation() {
George Karpenkovf893ea12018-11-30 02:17:44 +000064 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
George Karpenkov081c4772018-10-23 23:11:50 +000065 OtherStruct::doNothingToArray(arr);
66} // expected-warning{{Potential leak of an object stored into 'arr'}}
67 // expected-note@-1{{Object leaked}}
68
George Karpenkov3cfa04e2018-10-25 23:38:41 +000069void check_no_invalidation_other_struct() {
George Karpenkovf893ea12018-11-30 02:17:44 +000070 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
George Karpenkov3cfa04e2018-10-25 23:38:41 +000071 OtherStruct other(arr); // expected-warning{{Potential leak}}
72 // expected-note@-1{{Object leaked}}
73}
74
George Karpenkov6fd5c86d2018-10-31 17:38:29 +000075struct ArrayOwner : public OSObject {
76 OSArray *arr;
77 ArrayOwner(OSArray *arr) : arr(arr) {}
78
79 static ArrayOwner* create(OSArray *arr) {
80 return new ArrayOwner(arr);
81 }
82
83 OSArray *getArray() {
84 return arr;
85 }
86
87 OSArray *createArray() {
88 return OSArray::withCapacity(10);
89 }
90
91 OSArray *createArraySourceUnknown();
92
93 OSArray *getArraySourceUnknown();
94};
95
George Karpenkova1c3bb82018-11-30 02:17:31 +000096OSArray *generateArray() {
George Karpenkovf893ea12018-11-30 02:17:44 +000097 return OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
98 // expected-note@-1{{Call to function 'withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
George Karpenkova1c3bb82018-11-30 02:17:31 +000099}
100
101unsigned int check_leak_good_error_message() {
102 unsigned int out;
103 {
104 OSArray *leaked = generateArray(); // expected-note{{Calling 'generateArray'}}
105 // expected-note@-1{{Returning from 'generateArray'}}
106 out = leaked->getCount(); // expected-warning{{Potential leak of an object stored into 'leaked'}}
107 // 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}}
108 }
109 return out;
110}
111
112unsigned int check_leak_msg_temporary() {
George Karpenkovf893ea12018-11-30 02:17:44 +0000113 return generateArray()->getCount(); // expected-warning{{Potential leak of an object}}
114 // expected-note@-1{{Calling 'generateArray'}}
115 // expected-note@-2{{Returning from 'generateArray'}}
116 // 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 +0000117}
118
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000119void check_confusing_getters() {
120 OSArray *arr = OSArray::withCapacity(10);
121
122 ArrayOwner *AO = ArrayOwner::create(arr);
123 AO->getArray();
124
125 AO->release();
126 arr->release();
127}
128
George Karpenkov081c4772018-10-23 23:11:50 +0000129void check_rc_consumed() {
130 OSArray *arr = OSArray::withCapacity(10);
131 OSArray::consumeArray(arr);
132}
133
134void check_rc_consume_temporary() {
135 OSArray::consumeArray(OSArray::withCapacity(10));
136}
137
138void check_rc_getter() {
139 OSArray *arr = OSArray::MaskedGetter();
140 (void)arr;
141}
142
143void check_rc_create() {
144 OSArray *arr = OSArray::getOoopsActuallyCreate();
145 arr->release();
146}
147
148
George Karpenkov41dc8de2018-10-11 22:59:16 +0000149void check_dynamic_cast() {
150 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1));
151 arr->release();
152}
153
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000154unsigned int check_dynamic_cast_no_null_on_orig(OSObject *obj) {
155 OSArray *arr = OSDynamicCast(OSArray, obj);
156 if (arr) {
157 return arr->getCount();
158 } else {
159
160 // The fact that dynamic cast has failed should not imply that
161 // the input object was null.
162 return obj->foo(); // no-warning
163 }
164}
165
166void check_dynamic_cast_null_branch(OSObject *obj) {
167 OSArray *arr1 = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject}}
168 OSArray *arr = OSDynamicCast(OSArray, obj);
169 if (!arr) // expected-note{{Taking true branch}}
George Karpenkova1c3bb82018-11-30 02:17:31 +0000170 return; // expected-warning{{Potential leak of an object stored into 'arr1'}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000171 // expected-note@-1{{Object leaked}}
172 arr1->release();
173}
174
George Karpenkov41dc8de2018-10-11 22:59:16 +0000175void check_dynamic_cast_null_check() {
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000176 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); // expected-note{{Call to function 'generateObject' returns an OSObject}}
177 // expected-warning@-1{{Potential leak of an object}}
178 // expected-note@-2{{Object leaked}}
George Karpenkov41dc8de2018-10-11 22:59:16 +0000179 if (!arr)
180 return;
181 arr->release();
182}
183
George Karpenkovab0011e2018-08-23 00:26:59 +0000184void use_after_release() {
George Karpenkovf893ea12018-11-30 02:17:44 +0000185 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
George Karpenkovab0011e2018-08-23 00:26:59 +0000186 arr->release(); // expected-note{{Object released}}
187 arr->getCount(); // expected-warning{{Reference-counted object is used after it is released}}
188 // expected-note@-1{{Reference-counted object is used after it is released}}
189}
190
191void potential_leak() {
George Karpenkovf893ea12018-11-30 02:17:44 +0000192 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type OSArray with a +1 retain count}}
George Karpenkovab0011e2018-08-23 00:26:59 +0000193 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
194 arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}}
195 arr->getCount();
196} // expected-warning{{Potential leak of an object stored into 'arr'}}
197 // 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}}
198
199void proper_cleanup() {
200 OSArray *arr = OSArray::withCapacity(10); // +1
201 arr->retain(); // +2
202 arr->release(); // +1
203 arr->getCount();
204 arr->release(); // 0
205}
206
George Karpenkovab0011e2018-08-23 00:26:59 +0000207unsigned int no_warning_on_getter(ArrayOwner *owner) {
208 OSArray *arr = owner->getArray();
209 return arr->getCount();
210}
211
212unsigned int warn_on_overrelease(ArrayOwner *owner) {
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000213 // FIXME: summaries are not applied in case the source of the getter/setter
214 // is known.
215 // rdar://45681203
216 OSArray *arr = owner->getArray();
217 arr->release();
George Karpenkovab0011e2018-08-23 00:26:59 +0000218 return arr->getCount();
219}
220
221unsigned int nowarn_on_release_of_created(ArrayOwner *owner) {
222 OSArray *arr = owner->createArray();
223 unsigned int out = arr->getCount();
224 arr->release();
225 return out;
226}
227
228unsigned int nowarn_on_release_of_created_source_unknown(ArrayOwner *owner) {
229 OSArray *arr = owner->createArraySourceUnknown();
230 unsigned int out = arr->getCount();
231 arr->release();
232 return out;
233}
234
235unsigned int no_warn_ok_release(ArrayOwner *owner) {
236 OSArray *arr = owner->getArray(); // +0
237 arr->retain(); // +1
238 arr->release(); // +0
239 return arr->getCount(); // no-warning
240}
241
242unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) {
George Karpenkovf893ea12018-11-30 02:17:44 +0000243 OSArray *arr = owner->getArraySourceUnknown(); // expected-note{{function call returns an OSObject of type OSArray with a +0 retain count}}
George Karpenkovab0011e2018-08-23 00:26:59 +0000244 arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
245 // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
246 return arr->getCount();
247}
248
249unsigned int ok_release_with_unknown_source(ArrayOwner *owner) {
250 OSArray *arr = owner->getArraySourceUnknown(); // +0
251 arr->retain(); // +1
252 arr->release(); // +0
253 return arr->getCount();
254}