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 OSObject {
4   virtual void retain();
5   virtual void release();
6 
7   virtual ~OSObject(){}
8 };
9 
10 struct OSArray : public OSObject {
11   unsigned int getCount();
12 
13   static OSArray *withCapacity(unsigned int capacity);
14 };
15 
16 void use_after_release() {
17   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}}
18   arr->release(); // expected-note{{Object released}}
19   arr->getCount(); // expected-warning{{Reference-counted object is used after it is released}}
20                    // expected-note@-1{{Reference-counted object is used after it is released}}
21 }
22 
23 void potential_leak() {
24   OSArray *arr = OSArray::withCapacity(10); // expected-note{{Call to function 'withCapacity' returns an OSObject of type struct OSArray * with a +1 retain count}}
25   arr->retain(); // expected-note{{Reference count incremented. The object now has a +2 retain count}}
26   arr->release(); // expected-note{{Reference count decremented. The object now has a +1 retain count}}
27   arr->getCount();
28 } // expected-warning{{Potential leak of an object stored into 'arr'}}
29   // 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}}
30 
31 void proper_cleanup() {
32   OSArray *arr = OSArray::withCapacity(10); // +1
33   arr->retain(); // +2
34   arr->release(); // +1
35   arr->getCount();
36   arr->release(); // 0
37 }
38 
39 struct ArrayOwner {
40   OSArray *arr;
41 
42   OSArray *getArray() {
43     return arr;
44   }
45 
46   OSArray *createArray() {
47     return OSArray::withCapacity(10);
48   }
49 
50   OSArray *createArraySourceUnknown();
51 
52   OSArray *getArraySourceUnknown();
53 };
54 
55 //unsigned int leak_on_create_no_release(ArrayOwner *owner) {
56   //OSArray *myArray =
57 
58 //}
59 
60 unsigned int no_warning_on_getter(ArrayOwner *owner) {
61   OSArray *arr = owner->getArray();
62   return arr->getCount();
63 }
64 
65 unsigned int warn_on_overrelease(ArrayOwner *owner) {
66   OSArray *arr = owner->getArray(); // expected-note{{function call returns an OSObject of type struct OSArray * with a +0 retain count}}
67   arr->release(); // expected-warning{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
68                   // expected-note@-1{{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
69   return arr->getCount();
70 }
71 
72 unsigned int nowarn_on_release_of_created(ArrayOwner *owner) {
73   OSArray *arr = owner->createArray();
74   unsigned int out = arr->getCount();
75   arr->release();
76   return out;
77 }
78 
79 unsigned int nowarn_on_release_of_created_source_unknown(ArrayOwner *owner) {
80   OSArray *arr = owner->createArraySourceUnknown();
81   unsigned int out = arr->getCount();
82   arr->release();
83   return out;
84 }
85 
86 unsigned int no_warn_ok_release(ArrayOwner *owner) {
87   OSArray *arr = owner->getArray(); // +0
88   arr->retain(); // +1
89   arr->release(); // +0
90   return arr->getCount(); // no-warning
91 }
92 
93 unsigned int warn_on_overrelease_with_unknown_source(ArrayOwner *owner) {
94   OSArray *arr = owner->getArraySourceUnknown(); // 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 
100 unsigned int ok_release_with_unknown_source(ArrayOwner *owner) {
101   OSArray *arr = owner->getArraySourceUnknown(); // +0
102   arr->retain(); // +1
103   arr->release(); // +0
104   return arr->getCount();
105 }
106