blob: e9c9f698da3c4d74ed4dd261b1d3635553954550 [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
5#define OSTypeID(type) (type::metaClass)
6
7#define OSDynamicCast(type, inst) \
8 ((type *) OSMetaClassBase::safeMetaCast((inst), OSTypeID(type)))
9
George Karpenkovab0011e2018-08-23 00:26:59 +000010struct OSObject {
11 virtual void retain();
George Karpenkov48de5822018-10-23 23:11:30 +000012 virtual void release() {};
George Karpenkovab0011e2018-08-23 00:26:59 +000013 virtual ~OSObject(){}
George Karpenkov41dc8de2018-10-11 22:59:16 +000014
15 static OSObject *generateObject(int);
16
17 static const OSMetaClass * const metaClass;
George Karpenkovab0011e2018-08-23 00:26:59 +000018};
19
20struct OSArray : public OSObject {
21 unsigned int getCount();
22
23 static OSArray *withCapacity(unsigned int capacity);
George Karpenkov41dc8de2018-10-11 22:59:16 +000024
25 static const OSMetaClass * const metaClass;
George Karpenkovab0011e2018-08-23 00:26:59 +000026};
27
George Karpenkov41dc8de2018-10-11 22:59:16 +000028struct OSMetaClassBase {
29 static OSObject *safeMetaCast(const OSObject *inst, const OSMetaClass *meta);
30};
31
32void check_dynamic_cast() {
33 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1));
34 arr->release();
35}
36
37void check_dynamic_cast_null_check() {
38 OSArray *arr = OSDynamicCast(OSArray, OSObject::generateObject(1));
39 if (!arr)
40 return;
41 arr->release();
42}
43
George Karpenkovab0011e2018-08-23 00:26:59 +000044void use_after_release() {
45 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}}
46 arr->release(); // expected-note{{Object released}}
47 arr->getCount(); // expected-warning{{Reference-counted object is used after it is released}}
48 // expected-note@-1{{Reference-counted object is used after it is released}}
49}
50
51void potential_leak() {
52 OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}}
53 arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
54 arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}}
55 arr->getCount();
56} // expected-warning{{Potential leak of an object stored into 'arr'}}
57 // 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}}
58
59void proper_cleanup() {
60 OSArray *arr = OSArray::withCapacity(10); // +1
61 arr->retain(); // +2
62 arr->release(); // +1
63 arr->getCount();
64 arr->release(); // 0
65}
66
67struct ArrayOwner {
68 OSArray *arr;
69
70 OSArray *getArray() {
71 return arr;
72 }
73
74 OSArray *createArray() {
75 return OSArray::withCapacity(10);
76 }
77
78 OSArray *createArraySourceUnknown();
79
80 OSArray *getArraySourceUnknown();
81};
82
83//unsigned int leak_on_create_no_release(ArrayOwner *owner) {
84 //OSArray *myArray =
85
86//}
87
88unsigned int no_warning_on_getter(ArrayOwner *owner) {
89 OSArray *arr = owner->getArray();
90 return arr->getCount();
91}
92
93unsigned int warn_on_overrelease(ArrayOwner *owner) {
94 OSArray *arr = owner->getArray(); // expected-note{{function call returns an OSObject of type struct OSArray * with a +0 retain count}}
95 arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
96 // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
97 return arr->getCount();
98}
99
100unsigned int nowarn_on_release_of_created(ArrayOwner *owner) {
101 OSArray *arr = owner->createArray();
102 unsigned int out = arr->getCount();
103 arr->release();
104 return out;
105}
106
107unsigned int nowarn_on_release_of_created_source_unknown(ArrayOwner *owner) {
108 OSArray *arr = owner->createArraySourceUnknown();
109 unsigned int out = arr->getCount();
110 arr->release();
111 return out;
112}
113
114unsigned int no_warn_ok_release(ArrayOwner *owner) {
115 OSArray *arr = owner->getArray(); // +0
116 arr->retain(); // +1
117 arr->release(); // +0
118 return arr->getCount(); // no-warning
119}
120
121unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) {
122 OSArray *arr = owner->getArraySourceUnknown(); // expected-note{{function call returns an OSObject of type struct OSArray * with a +0 retain count}}
123 arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
124 // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
125 return arr->getCount();
126}
127
128unsigned int ok_release_with_unknown_source(ArrayOwner *owner) {
129 OSArray *arr = owner->getArraySourceUnknown(); // +0
130 arr->retain(); // +1
131 arr->release(); // +0
132 return arr->getCount();
133}