blob: 47601b0bada3e162176f6148d7ddd7a2240004be [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
26struct OSArray : public OSObject {
27 unsigned int getCount();
28
29 static OSArray *withCapacity(unsigned int capacity);
George Karpenkov081c4772018-10-23 23:11:50 +000030 static void consumeArray(OS_CONSUME OSArray * array);
31
32 static OSArray* consumeArrayHasCode(OS_CONSUME OSArray * array) {
33 return nullptr;
34 }
35
36 static OS_RETURNS_NOT_RETAINED OSArray *MaskedGetter();
37 static OS_RETURNS_RETAINED OSArray *getOoopsActuallyCreate();
38
George Karpenkov41dc8de2018-10-11 22:59:16 +000039
40 static const OSMetaClass * const metaClass;
George Karpenkovab0011e2018-08-23 00:26:59 +000041};
42
George Karpenkov081c4772018-10-23 23:11:50 +000043struct OtherStruct {
44 static void doNothingToArray(OSArray *array);
George Karpenkov3cfa04e2018-10-25 23:38:41 +000045 OtherStruct(OSArray *arr);
George Karpenkov081c4772018-10-23 23:11:50 +000046};
47
George Karpenkov41dc8de2018-10-11 22:59:16 +000048struct OSMetaClassBase {
49 static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta);
50};
51
George Karpenkov081c4772018-10-23 23:11:50 +000052void check_no_invalidation() {
53 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}}
54 OtherStruct::doNothingToArray(arr);
55} // expected-warning{{Potential leak of an object stored into 'arr'}}
56 // expected-note@-1{{Object leaked}}
57
George Karpenkov3cfa04e2018-10-25 23:38:41 +000058void check_no_invalidation_other_struct() {
59 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}}
60 OtherStruct other(arr); // expected-warning{{Potential leak}}
61 // expected-note@-1{{Object leaked}}
62}
63
George Karpenkov6fd5c86d2018-10-31 17:38:29 +000064struct ArrayOwner : public OSObject {
65 OSArray *arr;
66 ArrayOwner(OSArray *arr) : arr(arr) {}
67
68 static ArrayOwner* create(OSArray *arr) {
69 return new ArrayOwner(arr);
70 }
71
72 OSArray *getArray() {
73 return arr;
74 }
75
76 OSArray *createArray() {
77 return OSArray::withCapacity(10);
78 }
79
80 OSArray *createArraySourceUnknown();
81
82 OSArray *getArraySourceUnknown();
83};
84
85void check_confusing_getters() {
86 OSArray *arr = OSArray::withCapacity(10);
87
88 ArrayOwner *AO = ArrayOwner::create(arr);
89 AO->getArray();
90
91 AO->release();
92 arr->release();
93}
94
George Karpenkov081c4772018-10-23 23:11:50 +000095void check_rc_consumed() {
96 OSArray *arr = OSArray::withCapacity(10);
97 OSArray::consumeArray(arr);
98}
99
100void check_rc_consume_temporary() {
101 OSArray::consumeArray(OSArray::withCapacity(10));
102}
103
104void check_rc_getter() {
105 OSArray *arr = OSArray::MaskedGetter();
106 (void)arr;
107}
108
109void check_rc_create() {
110 OSArray *arr = OSArray::getOoopsActuallyCreate();
111 arr->release();
112}
113
114
George Karpenkov41dc8de2018-10-11 22:59:16 +0000115void check_dynamic_cast() {
116 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1));
117 arr->release();
118}
119
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000120unsigned int check_dynamic_cast_no_null_on_orig(OSObject *obj) {
121 OSArray *arr = OSDynamicCast(OSArray, obj);
122 if (arr) {
123 return arr->getCount();
124 } else {
125
126 // The fact that dynamic cast has failed should not imply that
127 // the input object was null.
128 return obj->foo(); // no-warning
129 }
130}
131
132void check_dynamic_cast_null_branch(OSObject *obj) {
133 OSArray *arr1 = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject}}
134 OSArray *arr = OSDynamicCast(OSArray, obj);
135 if (!arr) // expected-note{{Taking true branch}}
136 return; // expected-warning{{Potential leak}}
137 // expected-note@-1{{Object leaked}}
138 arr1->release();
139}
140
George Karpenkov41dc8de2018-10-11 22:59:16 +0000141void check_dynamic_cast_null_check() {
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000142 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); // expected-note{{Call to function 'generateObject' returns an OSObject}}
143 // expected-warning@-1{{Potential leak of an object}}
144 // expected-note@-2{{Object leaked}}
George Karpenkov41dc8de2018-10-11 22:59:16 +0000145 if (!arr)
146 return;
147 arr->release();
148}
149
George Karpenkovab0011e2018-08-23 00:26:59 +0000150void use_after_release() {
151 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}}
152 arr->release(); // expected-note{{Object released}}
153 arr->getCount(); // expected-warning{{Reference-counted object is used after it is released}}
154 // expected-note@-1{{Reference-counted object is used after it is released}}
155}
156
157void potential_leak() {
158 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}}
159 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
160 arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}}
161 arr->getCount();
162} // expected-warning{{Potential leak of an object stored into 'arr'}}
163 // 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}}
164
165void proper_cleanup() {
166 OSArray *arr = OSArray::withCapacity(10); // +1
167 arr->retain(); // +2
168 arr->release(); // +1
169 arr->getCount();
170 arr->release(); // 0
171}
172
George Karpenkovab0011e2018-08-23 00:26:59 +0000173unsigned int no_warning_on_getter(ArrayOwner *owner) {
174 OSArray *arr = owner->getArray();
175 return arr->getCount();
176}
177
178unsigned int warn_on_overrelease(ArrayOwner *owner) {
George Karpenkov6fd5c86d2018-10-31 17:38:29 +0000179 // FIXME: summaries are not applied in case the source of the getter/setter
180 // is known.
181 // rdar://45681203
182 OSArray *arr = owner->getArray();
183 arr->release();
George Karpenkovab0011e2018-08-23 00:26:59 +0000184 return arr->getCount();
185}
186
187unsigned int nowarn_on_release_of_created(ArrayOwner *owner) {
188 OSArray *arr = owner->createArray();
189 unsigned int out = arr->getCount();
190 arr->release();
191 return out;
192}
193
194unsigned int nowarn_on_release_of_created_source_unknown(ArrayOwner *owner) {
195 OSArray *arr = owner->createArraySourceUnknown();
196 unsigned int out = arr->getCount();
197 arr->release();
198 return out;
199}
200
201unsigned int no_warn_ok_release(ArrayOwner *owner) {
202 OSArray *arr = owner->getArray(); // +0
203 arr->retain(); // +1
204 arr->release(); // +0
205 return arr->getCount(); // no-warning
206}
207
208unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) {
209 OSArray *arr = owner->getArraySourceUnknown(); // expected-note{{function call returns an OSObject of type struct OSArray * with a +0 retain count}}
210 arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
211 // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
212 return arr->getCount();
213}
214
215unsigned int ok_release_with_unknown_source(ArrayOwner *owner) {
216 OSArray *arr = owner->getArraySourceUnknown(); // +0
217 arr->retain(); // +1
218 arr->release(); // +0
219 return arr->getCount();
220}