blob: 4e26c03bc26ea7ed5263bd8c39fc95fafd2c1767 [file] [log] [blame]
George Karpenkovab0011e2018-08-23 00:26:59 +00001// RUN: %clang_analyze_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-config osx.cocoa.RetainCount:CheckOSObject=true -analyzer-output=text -verify %s
2
George Karpenkov41dc8de2018-10-11 22:59:16 +00003struct OSMetaClass;
4
George Karpenkov081c4772018-10-23 23:11:50 +00005#define TRUSTED __attribute__((annotate("rc_ownership_trusted_implementation")))
6#define OS_CONSUME TRUSTED __attribute__((annotate("rc_ownership_consumed")))
7#define OS_RETURNS_RETAINED TRUSTED __attribute__((annotate("rc_ownership_returns_retained")))
8#define OS_RETURNS_NOT_RETAINED TRUSTED __attribute__((annotate("rc_ownership_returns_not_retained")))
9
George Karpenkov41dc8de2018-10-11 22:59:16 +000010#define OSTypeID(type) (type::metaClass)
11
12#define OSDynamicCast(type, inst) \
13 ((type *) OSMetaClassBase::safeMetaCast((inst), OSTypeID(type)))
14
George Karpenkovab0011e2018-08-23 00:26:59 +000015struct OSObject {
16 virtual void retain();
George Karpenkov48de5822018-10-23 23:11:30 +000017 virtual void release() {};
George Karpenkovab0011e2018-08-23 00:26:59 +000018 virtual ~OSObject(){}
George Karpenkov41dc8de2018-10-11 22:59:16 +000019
George Karpenkov3c2ed8f2018-10-25 23:38:07 +000020 unsigned int foo() { return 42; }
21
George Karpenkov41dc8de2018-10-11 22:59:16 +000022 static OSObject *generateObject(int);
23
24 static const OSMetaClass * const metaClass;
George Karpenkovab0011e2018-08-23 00:26:59 +000025};
26
27struct OSArray : public OSObject {
28 unsigned int getCount();
29
30 static OSArray *withCapacity(unsigned int capacity);
George Karpenkov081c4772018-10-23 23:11:50 +000031 static void consumeArray(OS_CONSUME OSArray * array);
32
33 static OSArray* consumeArrayHasCode(OS_CONSUME OSArray * array) {
34 return nullptr;
35 }
36
37 static OS_RETURNS_NOT_RETAINED OSArray *MaskedGetter();
38 static OS_RETURNS_RETAINED OSArray *getOoopsActuallyCreate();
39
George Karpenkov41dc8de2018-10-11 22:59:16 +000040
41 static const OSMetaClass * const metaClass;
George Karpenkovab0011e2018-08-23 00:26:59 +000042};
43
George Karpenkov081c4772018-10-23 23:11:50 +000044struct OtherStruct {
45 static void doNothingToArray(OSArray *array);
46};
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
58void check_rc_consumed() {
59 OSArray *arr = OSArray::withCapacity(10);
60 OSArray::consumeArray(arr);
61}
62
63void check_rc_consume_temporary() {
64 OSArray::consumeArray(OSArray::withCapacity(10));
65}
66
67void check_rc_getter() {
68 OSArray *arr = OSArray::MaskedGetter();
69 (void)arr;
70}
71
72void check_rc_create() {
73 OSArray *arr = OSArray::getOoopsActuallyCreate();
74 arr->release();
75}
76
77
George Karpenkov41dc8de2018-10-11 22:59:16 +000078void check_dynamic_cast() {
79 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1));
80 arr->release();
81}
82
George Karpenkov3c2ed8f2018-10-25 23:38:07 +000083unsigned int check_dynamic_cast_no_null_on_orig(OSObject *obj) {
84 OSArray *arr = OSDynamicCast(OSArray, obj);
85 if (arr) {
86 return arr->getCount();
87 } else {
88
89 // The fact that dynamic cast has failed should not imply that
90 // the input object was null.
91 return obj->foo(); // no-warning
92 }
93}
94
95void check_dynamic_cast_null_branch(OSObject *obj) {
96 OSArray *arr1 = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject}}
97 OSArray *arr = OSDynamicCast(OSArray, obj);
98 if (!arr) // expected-note{{Taking true branch}}
99 return; // expected-warning{{Potential leak}}
100 // expected-note@-1{{Object leaked}}
101 arr1->release();
102}
103
George Karpenkov41dc8de2018-10-11 22:59:16 +0000104void check_dynamic_cast_null_check() {
George Karpenkov3c2ed8f2018-10-25 23:38:07 +0000105 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); // expected-note{{Call to function 'generateObject' returns an OSObject}}
106 // expected-warning@-1{{Potential leak of an object}}
107 // expected-note@-2{{Object leaked}}
George Karpenkov41dc8de2018-10-11 22:59:16 +0000108 if (!arr)
109 return;
110 arr->release();
111}
112
George Karpenkovab0011e2018-08-23 00:26:59 +0000113void use_after_release() {
114 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}}
115 arr->release(); // expected-note{{Object released}}
116 arr->getCount(); // expected-warning{{Reference-counted object is used after it is released}}
117 // expected-note@-1{{Reference-counted object is used after it is released}}
118}
119
120void potential_leak() {
121 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}}
122 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
123 arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}}
124 arr->getCount();
125} // expected-warning{{Potential leak of an object stored into 'arr'}}
126 // 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}}
127
128void proper_cleanup() {
129 OSArray *arr = OSArray::withCapacity(10); // +1
130 arr->retain(); // +2
131 arr->release(); // +1
132 arr->getCount();
133 arr->release(); // 0
134}
135
136struct ArrayOwner {
137 OSArray *arr;
138
139 OSArray *getArray() {
140 return arr;
141 }
142
143 OSArray *createArray() {
144 return OSArray::withCapacity(10);
145 }
146
147 OSArray *createArraySourceUnknown();
148
149 OSArray *getArraySourceUnknown();
150};
151
George Karpenkovab0011e2018-08-23 00:26:59 +0000152unsigned int no_warning_on_getter(ArrayOwner *owner) {
153 OSArray *arr = owner->getArray();
154 return arr->getCount();
155}
156
157unsigned int warn_on_overrelease(ArrayOwner *owner) {
158 OSArray *arr = owner->getArray(); // expected-note{{function call returns an OSObject of type struct OSArray * with a +0 retain count}}
159 arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
160 // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
161 return arr->getCount();
162}
163
164unsigned int nowarn_on_release_of_created(ArrayOwner *owner) {
165 OSArray *arr = owner->createArray();
166 unsigned int out = arr->getCount();
167 arr->release();
168 return out;
169}
170
171unsigned int nowarn_on_release_of_created_source_unknown(ArrayOwner *owner) {
172 OSArray *arr = owner->createArraySourceUnknown();
173 unsigned int out = arr->getCount();
174 arr->release();
175 return out;
176}
177
178unsigned int no_warn_ok_release(ArrayOwner *owner) {
179 OSArray *arr = owner->getArray(); // +0
180 arr->retain(); // +1
181 arr->release(); // +0
182 return arr->getCount(); // no-warning
183}
184
185unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) {
186 OSArray *arr = owner->getArraySourceUnknown(); // expected-note{{function call returns an OSObject of type struct OSArray * with a +0 retain count}}
187 arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
188 // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
189 return arr->getCount();
190}
191
192unsigned int ok_release_with_unknown_source(ArrayOwner *owner) {
193 OSArray *arr = owner->getArraySourceUnknown(); // +0
194 arr->retain(); // +1
195 arr->release(); // +0
196 return arr->getCount();
197}