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   static OSObject *generateObject(int);
21 
22   static const OSMetaClass * const metaClass;
23 };
24 
25 struct OSArray : public OSObject {
26   unsigned int getCount();
27 
28   static OSArray *withCapacity(unsigned int capacity);
29   static void consumeArray(OS_CONSUME OSArray * array);
30 
31   static OSArray* consumeArrayHasCode(OS_CONSUME OSArray * array) {
32     return nullptr;
33   }
34 
35   static OS_RETURNS_NOT_RETAINED OSArray *MaskedGetter();
36   static OS_RETURNS_RETAINED OSArray *getOoopsActuallyCreate();
37 
38 
39   static const OSMetaClass * const metaClass;
40 };
41 
42 struct OtherStruct {
43   static void doNothingToArray(OSArray *array);
44 };
45 
46 struct OSMetaClassBase {
47   static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta);
48 };
49 
50 void check_no_invalidation() {
51   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}}
52   OtherStruct::doNothingToArray(arr);
53 } // expected-warning{{Potential leak of an object stored into 'arr'}}
54   // expected-note@-1{{Object leaked}}
55 
56 void check_rc_consumed() {
57   OSArray *arr = OSArray::withCapacity(10);
58   OSArray::consumeArray(arr);
59 }
60 
61 void check_rc_consume_temporary() {
62   OSArray::consumeArray(OSArray::withCapacity(10));
63 }
64 
65 void check_rc_getter() {
66   OSArray *arr = OSArray::MaskedGetter();
67   (void)arr;
68 }
69 
70 void check_rc_create() {
71   OSArray *arr = OSArray::getOoopsActuallyCreate();
72   arr->release();
73 }
74 
75 
76 void check_dynamic_cast() {
77   OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1));
78   arr->release();
79 }
80 
81 void check_dynamic_cast_null_check() {
82   OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1));
83   if (!arr)
84     return;
85   arr->release();
86 }
87 
88 void use_after_release() {
89   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}}
90   arr->release(); // expected-note{{Object released}}
91   arr->getCount(); // expected-warning{{Reference-counted object is used after it is released}}
92                    // expected-note@-1{{Reference-counted object is used after it is released}}
93 }
94 
95 void potential_leak() {
96   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}}
97   arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
98   arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}}
99   arr->getCount();
100 } // expected-warning{{Potential leak of an object stored into 'arr'}}
101   // 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}}
102 
103 void proper_cleanup() {
104   OSArray *arr = OSArray::withCapacity(10); // +1
105   arr->retain(); // +2
106   arr->release(); // +1
107   arr->getCount();
108   arr->release(); // 0
109 }
110 
111 struct ArrayOwner {
112   OSArray *arr;
113 
114   OSArray *getArray() {
115     return arr;
116   }
117 
118   OSArray *createArray() {
119     return OSArray::withCapacity(10);
120   }
121 
122   OSArray *createArraySourceUnknown();
123 
124   OSArray *getArraySourceUnknown();
125 };
126 
127 unsigned int no_warning_on_getter(ArrayOwner *owner) {
128   OSArray *arr = owner->getArray();
129   return arr->getCount();
130 }
131 
132 unsigned int warn_on_overrelease(ArrayOwner *owner) {
133   OSArray *arr = owner->getArray(); // expected-note{{function call returns an OSObject of type struct OSArray * with a +0 retain count}}
134   arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
135                   // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
136   return arr->getCount();
137 }
138 
139 unsigned int nowarn_on_release_of_created(ArrayOwner *owner) {
140   OSArray *arr = owner->createArray();
141   unsigned int out = arr->getCount();
142   arr->release();
143   return out;
144 }
145 
146 unsigned int nowarn_on_release_of_created_source_unknown(ArrayOwner *owner) {
147   OSArray *arr = owner->createArraySourceUnknown();
148   unsigned int out = arr->getCount();
149   arr->release();
150   return out;
151 }
152 
153 unsigned int no_warn_ok_release(ArrayOwner *owner) {
154   OSArray *arr = owner->getArray(); // +0
155   arr->retain(); // +1
156   arr->release(); // +0
157   return arr->getCount(); // no-warning
158 }
159 
160 unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) {
161   OSArray *arr = owner->getArraySourceUnknown(); // expected-note{{function call returns an OSObject of type struct OSArray * with a +0 retain count}}
162   arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
163                   // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
164   return arr->getCount();
165 }
166 
167 unsigned int ok_release_with_unknown_source(ArrayOwner *owner) {
168   OSArray *arr = owner->getArraySourceUnknown(); // +0
169   arr->retain(); // +1
170   arr->release(); // +0
171   return arr->getCount();
172 }
173