blob: 23e92ecaf6b203dee56e1e32dd5c56544605e75b [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
20 static OSObject *generateObject(int);
21
22 static const OSMetaClass * const metaClass;
George Karpenkovab0011e2018-08-23 00:26:59 +000023};
24
25struct OSArray : public OSObject {
26 unsigned int getCount();
27
28 static OSArray *withCapacity(unsigned int capacity);
George Karpenkov081c4772018-10-23 23:11:50 +000029 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
George Karpenkov41dc8de2018-10-11 22:59:16 +000038
39 static const OSMetaClass * const metaClass;
George Karpenkovab0011e2018-08-23 00:26:59 +000040};
41
George Karpenkov081c4772018-10-23 23:11:50 +000042struct OtherStruct {
43 static void doNothingToArray(OSArray *array);
44};
45
George Karpenkov41dc8de2018-10-11 22:59:16 +000046struct OSMetaClassBase {
47 static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta);
48};
49
George Karpenkov081c4772018-10-23 23:11:50 +000050void 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
56void check_rc_consumed() {
57 OSArray *arr = OSArray::withCapacity(10);
58 OSArray::consumeArray(arr);
59}
60
61void check_rc_consume_temporary() {
62 OSArray::consumeArray(OSArray::withCapacity(10));
63}
64
65void check_rc_getter() {
66 OSArray *arr = OSArray::MaskedGetter();
67 (void)arr;
68}
69
70void check_rc_create() {
71 OSArray *arr = OSArray::getOoopsActuallyCreate();
72 arr->release();
73}
74
75
George Karpenkov41dc8de2018-10-11 22:59:16 +000076void check_dynamic_cast() {
77 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1));
78 arr->release();
79}
80
81void check_dynamic_cast_null_check() {
82 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1));
83 if (!arr)
84 return;
85 arr->release();
86}
87
George Karpenkovab0011e2018-08-23 00:26:59 +000088void 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
95void 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
103void 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
111struct 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
George Karpenkovab0011e2018-08-23 00:26:59 +0000127unsigned int no_warning_on_getter(ArrayOwner *owner) {
128 OSArray *arr = owner->getArray();
129 return arr->getCount();
130}
131
132unsigned 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
139unsigned 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
146unsigned 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
153unsigned 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
160unsigned 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
167unsigned 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}