1 // RUN: %clang_analyze_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-output=text -verify %s
2 
3 struct OSMetaClass;
4 
5 #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")))
8 
9 #define OSTypeID(type)   (type::metaClass)
10 
11 #define OSDynamicCast(type, inst)   \
12     ((type *) OSMetaClassBase::safeMetaCast((inst), OSTypeID(type)))
13 
14 struct OSObject {
15   virtual void retain();
16   virtual void release() {};
17   virtual ~OSObject(){}
18 
19   unsigned int foo() { return 42; }
20 
21   static OSObject *generateObject(int);
22 
23   static const OSMetaClass * const metaClass;
24 };
25 
26 struct OSIterator : public OSObject {
27 };
28 
29 struct OSArray : public OSObject {
30   unsigned int getCount();
31 
32   static OSArray *withCapacity(unsigned int capacity);
33   static void consumeArray(OS_CONSUME OSArray * array);
34 
35   static OSArray* consumeArrayHasCode(OS_CONSUME OSArray * array) {
36     return nullptr;
37   }
38 
39   OSIterator * getIterator();
40 
41   static OS_RETURNS_NOT_RETAINED OSArray *MaskedGetter();
42   static OS_RETURNS_RETAINED OSArray *getOoopsActuallyCreate();
43 
44 
45   static const OSMetaClass * const metaClass;
46 };
47 
48 struct OtherStruct {
49   static void doNothingToArray(OSArray *array);
50   OtherStruct(OSArray *arr);
51 };
52 
53 struct OSMetaClassBase {
54   static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta);
55 };
56 
57 void check_custom_iterator_rule(OSArray *arr) {
58   OSIterator *it = arr->getIterator();
59   it->release();
60 }
61 
62 void 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 
68 void 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 
74 struct 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 
95 void 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 
105 void check_rc_consumed() {
106   OSArray *arr = OSArray::withCapacity(10);
107   OSArray::consumeArray(arr);
108 }
109 
110 void check_rc_consume_temporary() {
111   OSArray::consumeArray(OSArray::withCapacity(10));
112 }
113 
114 void check_rc_getter() {
115   OSArray *arr = OSArray::MaskedGetter();
116   (void)arr;
117 }
118 
119 void check_rc_create() {
120   OSArray *arr = OSArray::getOoopsActuallyCreate();
121   arr->release();
122 }
123 
124 
125 void check_dynamic_cast() {
126   OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1));
127   arr->release();
128 }
129 
130 unsigned 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 
142 void 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 
151 void check_dynamic_cast_null_check() {
152   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}}
155   if (!arr)
156     return;
157   arr->release();
158 }
159 
160 void 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 
167 void 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 
175 void 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 
183 unsigned int no_warning_on_getter(ArrayOwner *owner) {
184   OSArray *arr = owner->getArray();
185   return arr->getCount();
186 }
187 
188 unsigned int warn_on_overrelease(ArrayOwner *owner) {
189   // 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();
194   return arr->getCount();
195 }
196 
197 unsigned 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 
204 unsigned 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 
211 unsigned 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 
218 unsigned 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 
225 unsigned 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 }
231