1 // RUN: %clang_analyze_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-config osx.cocoa.RetainCount:CheckOSObject=true -analyzer-output=text -verify %s
2 
3 struct OSMetaClass;
4 
5 #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 
10 #define OSTypeID(type)   (type::metaClass)
11 
12 #define OSDynamicCast(type, inst)   \
13     ((type *) OSMetaClassBase::safeMetaCast((inst), OSTypeID(type)))
14 
15 struct OSObject {
16   virtual void retain();
17   virtual void release() {};
18   virtual ~OSObject(){}
19 
20   unsigned int foo() { return 42; }
21 
22   static OSObject *generateObject(int);
23 
24   static const OSMetaClass * const metaClass;
25 };
26 
27 struct OSArray : public OSObject {
28   unsigned int getCount();
29 
30   static OSArray *withCapacity(unsigned int capacity);
31   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 
40 
41   static const OSMetaClass * const metaClass;
42 };
43 
44 struct OtherStruct {
45   static void doNothingToArray(OSArray *array);
46   OtherStruct(OSArray *arr);
47 };
48 
49 struct OSMetaClassBase {
50   static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta);
51 };
52 
53 void check_no_invalidation() {
54   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}}
55   OtherStruct::doNothingToArray(arr);
56 } // expected-warning{{Potential leak of an object stored into 'arr'}}
57   // expected-note@-1{{Object leaked}}
58 
59 void check_no_invalidation_other_struct() {
60   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}}
61   OtherStruct other(arr); // expected-warning{{Potential leak}}
62                           // expected-note@-1{{Object leaked}}
63 }
64 
65 void check_rc_consumed() {
66   OSArray *arr = OSArray::withCapacity(10);
67   OSArray::consumeArray(arr);
68 }
69 
70 void check_rc_consume_temporary() {
71   OSArray::consumeArray(OSArray::withCapacity(10));
72 }
73 
74 void check_rc_getter() {
75   OSArray *arr = OSArray::MaskedGetter();
76   (void)arr;
77 }
78 
79 void check_rc_create() {
80   OSArray *arr = OSArray::getOoopsActuallyCreate();
81   arr->release();
82 }
83 
84 
85 void check_dynamic_cast() {
86   OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1));
87   arr->release();
88 }
89 
90 unsigned int check_dynamic_cast_no_null_on_orig(OSObject *obj) {
91   OSArray *arr = OSDynamicCast(OSArray, obj);
92   if (arr) {
93     return arr->getCount();
94   } else {
95 
96     // The fact that dynamic cast has failed should not imply that
97     // the input object was null.
98     return obj->foo(); // no-warning
99   }
100 }
101 
102 void check_dynamic_cast_null_branch(OSObject *obj) {
103   OSArray *arr1 = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject}}
104   OSArray *arr = OSDynamicCast(OSArray, obj);
105   if (!arr) // expected-note{{Taking true branch}}
106     return; // expected-warning{{Potential leak}}
107             // expected-note@-1{{Object leaked}}
108   arr1->release();
109 }
110 
111 void check_dynamic_cast_null_check() {
112   OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1)); // expected-note{{Call to function 'generateObject' returns an OSObject}}
113     // expected-warning@-1{{Potential leak of an object}}
114     // expected-note@-2{{Object leaked}}
115   if (!arr)
116     return;
117   arr->release();
118 }
119 
120 void use_after_release() {
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->release(); // expected-note{{Object released}}
123   arr->getCount(); // expected-warning{{Reference-counted object is used after it is released}}
124                    // expected-note@-1{{Reference-counted object is used after it is released}}
125 }
126 
127 void potential_leak() {
128   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}}
129   arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
130   arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}}
131   arr->getCount();
132 } // expected-warning{{Potential leak of an object stored into 'arr'}}
133   // 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}}
134 
135 void proper_cleanup() {
136   OSArray *arr = OSArray::withCapacity(10); // +1
137   arr->retain(); // +2
138   arr->release(); // +1
139   arr->getCount();
140   arr->release(); // 0
141 }
142 
143 struct ArrayOwner {
144   OSArray *arr;
145 
146   OSArray *getArray() {
147     return arr;
148   }
149 
150   OSArray *createArray() {
151     return OSArray::withCapacity(10);
152   }
153 
154   OSArray *createArraySourceUnknown();
155 
156   OSArray *getArraySourceUnknown();
157 };
158 
159 unsigned int no_warning_on_getter(ArrayOwner *owner) {
160   OSArray *arr = owner->getArray();
161   return arr->getCount();
162 }
163 
164 unsigned int warn_on_overrelease(ArrayOwner *owner) {
165   OSArray *arr = owner->getArray(); // expected-note{{function call returns an OSObject of type struct OSArray * with a +0 retain count}}
166   arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
167                   // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
168   return arr->getCount();
169 }
170 
171 unsigned int nowarn_on_release_of_created(ArrayOwner *owner) {
172   OSArray *arr = owner->createArray();
173   unsigned int out = arr->getCount();
174   arr->release();
175   return out;
176 }
177 
178 unsigned int nowarn_on_release_of_created_source_unknown(ArrayOwner *owner) {
179   OSArray *arr = owner->createArraySourceUnknown();
180   unsigned int out = arr->getCount();
181   arr->release();
182   return out;
183 }
184 
185 unsigned int no_warn_ok_release(ArrayOwner *owner) {
186   OSArray *arr = owner->getArray(); // +0
187   arr->retain(); // +1
188   arr->release(); // +0
189   return arr->getCount(); // no-warning
190 }
191 
192 unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) {
193   OSArray *arr = owner->getArraySourceUnknown(); // expected-note{{function call returns an OSObject of type struct OSArray * with a +0 retain count}}
194   arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
195                   // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
196   return arr->getCount();
197 }
198 
199 unsigned int ok_release_with_unknown_source(ArrayOwner *owner) {
200   OSArray *arr = owner->getArraySourceUnknown(); // +0
201   arr->retain(); // +1
202   arr->release(); // +0
203   return arr->getCount();
204 }
205