blob: 71f912961d3b5a61a00fae61cb11d0b26389c3bd [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 {
27};
28
George Karpenkovab0011e2018-08-23 00:26:59 +000029struct OSArray : public OSObject {
30 unsigned int getCount();
31
32 static OSArray *withCapacity(unsigned int capacity);
George Karpenkov081c4772018-10-23 23:11:50 +000033 static void consumeArray(OS_CONSUME OSArray * array);
34
35 static OSArray* consumeArrayHasCode(OS_CONSUME OSArray * array) {
36 return nullptr;
37 }
38
George Karpenkov83fb5362018-10-31 17:38:46 +000039 OSIterator * getIterator();
40
George Karpenkov081c4772018-10-23 23:11:50 +000041 static OS_RETURNS_NOT_RETAINED OSArray *MaskedGetter();
42 static OS_RETURNS_RETAINED OSArray *getOoopsActuallyCreate();
43
George Karpenkov41dc8de2018-10-11 22:59:16 +000044
45 static const OSMetaClass * const metaClass;
George Karpenkovab0011e2018-08-23 00:26:59 +000046};
47
George Karpenkov081c4772018-10-23 23:11:50 +000048struct OtherStruct {
49 static void doNothingToArray(OSArray *array);
George Karpenkov3cfa04e2018-10-25 23:38:41 +000050 OtherStruct(OSArray *arr);
George Karpenkov081c4772018-10-23 23:11:50 +000051};
52
George Karpenkov41dc8de2018-10-11 22:59:16 +000053struct OSMetaClassBase {
54 static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta);
55};
56
George Karpenkov83fb5362018-10-31 17:38:46 +000057void check_custom_iterator_rule(OSArray *arr) {
58 OSIterator *it = arr->getIterator();
59 it->release();
60}
61
George Karpenkov081c4772018-10-23 23:11:50 +000062void check_no_invalidation() {
63 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}}
64 OtherStruct::doNothingToArray(arr);
65} // expected-warning{{Potential leak of an object stored into 'arr'}}
66 // expected-note@-1{{Object leaked}}
67
George Karpenkov3cfa04e2018-10-25 23:38:41 +000068void check_no_invalidation_other_struct() {
69 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}}
70 OtherStruct other(arr); // expected-warning{{Potential leak}}
71 // expected-note@-1{{Object leaked}}
72}
73
George Karpenkov6fd5c86d2018-10-31 17:38:29 +000074struct ArrayOwner : public OSObject {
75 OSArray *arr;
76 ArrayOwner(OSArray *arr) : arr(arr) {}
77
78 static ArrayOwner* create(OSArray *arr) {
79 return new ArrayOwner(arr);
80 }
81
82 OSArray *getArray() {
83 return arr;
84 }
85
86 OSArray *createArray() {
87 return OSArray::withCapacity(10);
88 }
89
90 OSArray *createArraySourceUnknown();
91
92 OSArray *getArraySourceUnknown();
93};
94
95void check_confusing_getters() {
96 OSArray *arr = OSArray::withCapacity(10);
97
98 ArrayOwner *AO = ArrayOwner::create(arr);
99 AO->getArray();
100
101 AO->release();
102 arr->release();
103}
104
George Karpenkov081c4772018-10-23 23:11:50 +0000105void check_rc_consumed() {
106 OSArray *arr = OSArray::withCapacity(10);
107 OSArray::consumeArray(arr);
108}
109
110void check_rc_consume_temporary() {
111 OSArray::consumeArray(OSArray::withCapacity(10));
112}
113
114void check_rc_getter() {
115 OSArray *arr = OSArray::MaskedGetter();
116 (void)arr;
117}
118
119void check_rc_create() {
120 OSArray *arr = OSArray::getOoopsActuallyCreate();
121 arr->release();
122}
123
124
George Karpenkov41dc8de2018-10-11 22:59:16 +0000125void check_dynamic_cast() {
126 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1));
127 arr->release();
128}
129
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000130unsigned int check_dynamic_cast_no_null_on_orig(OSObject *obj) {
131 OSArray *arr = OSDynamicCast(OSArray, obj);
132 if (arr) {
133 return arr->getCount();
134 } else {
135
136 // The fact that dynamic cast has failed should not imply that
137 // the input object was null.
138 return obj->foo(); // no-warning
139 }
140}
141
142void check_dynamic_cast_null_branch(OSObject *obj) {
143 OSArray *arr1 = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject}}
144 OSArray *arr = OSDynamicCast(OSArray, obj);
145 if (!arr) // expected-note{{Taking true branch}}
146 return; // expected-warning{{Potential leak}}
147 // expected-note@-1{{Object leaked}}
148 arr1->release();
149}
150
George Karpenkov41dc8de2018-10-11 22:59:16 +0000151void check_dynamic_cast_null_check() {
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000152 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); // expected-note{{Call to function 'generateObject' returns an OSObject}}
153 // expected-warning@-1{{Potential leak of an object}}
154 // expected-note@-2{{Object leaked}}
George Karpenkov41dc8de2018-10-11 22:59:16 +0000155 if (!arr)
156 return;
157 arr->release();
158}
159
George Karpenkovab0011e2018-08-23 00:26:59 +0000160void use_after_release() {
161 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}}
162 arr->release(); // expected-note{{Object released}}
163 arr->getCount(); // expected-warning{{Reference-counted object is used after it is released}}
164 // expected-note@-1{{Reference-counted object is used after it is released}}
165}
166
167void potential_leak() {
168 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}}
169 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
170 arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}}
171 arr->getCount();
172} // expected-warning{{Potential leak of an object stored into 'arr'}}
173 // 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}}
174
175void proper_cleanup() {
176 OSArray *arr = OSArray::withCapacity(10); // +1
177 arr->retain(); // +2
178 arr->release(); // +1
179 arr->getCount();
180 arr->release(); // 0
181}
182
George Karpenkovab0011e2018-08-23 00:26:59 +0000183unsigned int no_warning_on_getter(ArrayOwner *owner) {
184 OSArray *arr = owner->getArray();
185 return arr->getCount();
186}
187
188unsigned int warn_on_overrelease(ArrayOwner *owner) {
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000189 // FIXME: summaries are not applied in case the source of the getter/setter
190 // is known.
191 // rdar://45681203
192 OSArray *arr = owner->getArray();
193 arr->release();
George Karpenkovab0011e2018-08-23 00:26:59 +0000194 return arr->getCount();
195}
196
197unsigned int nowarn_on_release_of_created(ArrayOwner *owner) {
198 OSArray *arr = owner->createArray();
199 unsigned int out = arr->getCount();
200 arr->release();
201 return out;
202}
203
204unsigned int nowarn_on_release_of_created_source_unknown(ArrayOwner *owner) {
205 OSArray *arr = owner->createArraySourceUnknown();
206 unsigned int out = arr->getCount();
207 arr->release();
208 return out;
209}
210
211unsigned int no_warn_ok_release(ArrayOwner *owner) {
212 OSArray *arr = owner->getArray(); // +0
213 arr->retain(); // +1
214 arr->release(); // +0
215 return arr->getCount(); // no-warning
216}
217
218unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) {
219 OSArray *arr = owner->getArraySourceUnknown(); // expected-note{{function call returns an OSObject of type struct OSArray * with a +0 retain count}}
220 arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
221 // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
222 return arr->getCount();
223}
224
225unsigned int ok_release_with_unknown_source(ArrayOwner *owner) {
226 OSArray *arr = owner->getArraySourceUnknown(); // +0
227 arr->retain(); // +1
228 arr->release(); // +0
229 return arr->getCount();
230}