blob: e02feef6fe4555a99655f9d75cec1295a4740658 [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() {
64 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}}
65 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() {
70 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}}
71 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() {
97 return OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}}
98}
99
100unsigned int check_leak_good_error_message() {
101 unsigned int out;
102 {
103 OSArray *leaked = generateArray(); // expected-note{{Calling 'generateArray'}}
104 // expected-note@-1{{Returning from 'generateArray'}}
105 out = leaked->getCount(); // expected-warning{{Potential leak of an object stored into 'leaked'}}
106 // 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}}
107 }
108 return out;
109}
110
111unsigned int check_leak_msg_temporary() {
112 return generateArray()->getCount();
113}
114
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000115void check_confusing_getters() {
116 OSArray *arr = OSArray::withCapacity(10);
117
118 ArrayOwner *AO = ArrayOwner::create(arr);
119 AO->getArray();
120
121 AO->release();
122 arr->release();
123}
124
George Karpenkov081c4772018-10-23 23:11:50 +0000125void check_rc_consumed() {
126 OSArray *arr = OSArray::withCapacity(10);
127 OSArray::consumeArray(arr);
128}
129
130void check_rc_consume_temporary() {
131 OSArray::consumeArray(OSArray::withCapacity(10));
132}
133
134void check_rc_getter() {
135 OSArray *arr = OSArray::MaskedGetter();
136 (void)arr;
137}
138
139void check_rc_create() {
140 OSArray *arr = OSArray::getOoopsActuallyCreate();
141 arr->release();
142}
143
144
George Karpenkov41dc8de2018-10-11 22:59:16 +0000145void check_dynamic_cast() {
146 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1));
147 arr->release();
148}
149
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000150unsigned int check_dynamic_cast_no_null_on_orig(OSObject *obj) {
151 OSArray *arr = OSDynamicCast(OSArray, obj);
152 if (arr) {
153 return arr->getCount();
154 } else {
155
156 // The fact that dynamic cast has failed should not imply that
157 // the input object was null.
158 return obj->foo(); // no-warning
159 }
160}
161
162void check_dynamic_cast_null_branch(OSObject *obj) {
163 OSArray *arr1 = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject}}
164 OSArray *arr = OSDynamicCast(OSArray, obj);
165 if (!arr) // expected-note{{Taking true branch}}
George Karpenkova1c3bb82018-11-30 02:17:31 +0000166 return; // expected-warning{{Potential leak of an object stored into 'arr1'}}
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000167 // expected-note@-1{{Object leaked}}
168 arr1->release();
169}
170
George Karpenkov41dc8de2018-10-11 22:59:16 +0000171void check_dynamic_cast_null_check() {
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000172 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); // expected-note{{Call to function 'generateObject' returns an OSObject}}
173 // expected-warning@-1{{Potential leak of an object}}
174 // expected-note@-2{{Object leaked}}
George Karpenkov41dc8de2018-10-11 22:59:16 +0000175 if (!arr)
176 return;
177 arr->release();
178}
179
George Karpenkovab0011e2018-08-23 00:26:59 +0000180void use_after_release() {
181 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}}
182 arr->release(); // expected-note{{Object released}}
183 arr->getCount(); // expected-warning{{Reference-counted object is used after it is released}}
184 // expected-note@-1{{Reference-counted object is used after it is released}}
185}
186
187void potential_leak() {
188 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}}
189 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
190 arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}}
191 arr->getCount();
192} // expected-warning{{Potential leak of an object stored into 'arr'}}
193 // 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}}
194
195void proper_cleanup() {
196 OSArray *arr = OSArray::withCapacity(10); // +1
197 arr->retain(); // +2
198 arr->release(); // +1
199 arr->getCount();
200 arr->release(); // 0
201}
202
George Karpenkovab0011e2018-08-23 00:26:59 +0000203unsigned int no_warning_on_getter(ArrayOwner *owner) {
204 OSArray *arr = owner->getArray();
205 return arr->getCount();
206}
207
208unsigned int warn_on_overrelease(ArrayOwner *owner) {
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000209 // FIXME: summaries are not applied in case the source of the getter/setter
210 // is known.
211 // rdar://45681203
212 OSArray *arr = owner->getArray();
213 arr->release();
George Karpenkovab0011e2018-08-23 00:26:59 +0000214 return arr->getCount();
215}
216
217unsigned int nowarn_on_release_of_created(ArrayOwner *owner) {
218 OSArray *arr = owner->createArray();
219 unsigned int out = arr->getCount();
220 arr->release();
221 return out;
222}
223
224unsigned int nowarn_on_release_of_created_source_unknown(ArrayOwner *owner) {
225 OSArray *arr = owner->createArraySourceUnknown();
226 unsigned int out = arr->getCount();
227 arr->release();
228 return out;
229}
230
231unsigned int no_warn_ok_release(ArrayOwner *owner) {
232 OSArray *arr = owner->getArray(); // +0
233 arr->retain(); // +1
234 arr->release(); // +0
235 return arr->getCount(); // no-warning
236}
237
238unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) {
239 OSArray *arr = owner->getArraySourceUnknown(); // expected-note{{function call returns an OSObject of type struct OSArray * with a +0 retain count}}
240 arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
241 // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
242 return arr->getCount();
243}
244
245unsigned int ok_release_with_unknown_source(ArrayOwner *owner) {
246 OSArray *arr = owner->getArraySourceUnknown(); // +0
247 arr->retain(); // +1
248 arr->release(); // +0
249 return arr->getCount();
250}