1 | // RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,osx.cocoa.RetainCount,deadcode -verify -fblocks -analyzer-opt-analyze-nested-blocks -fobjc-arc -analyzer-output=plist-multi-file -o %t.plist %s |
2 | // RUN: cat %t.plist | %diff_plist %S/Inputs/expected-plists/objc-arc.m.plist - |
3 | |
4 | typedef signed char BOOL; |
5 | typedef struct _NSZone NSZone; |
6 | @class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; |
7 | typedef unsigned long NSUInteger; |
8 | |
9 | @protocol NSObject |
10 | - (BOOL)isEqual:(id)object; |
11 | @end |
12 | @protocol NSCopying |
13 | - (id)copyWithZone:(NSZone *)zone; |
14 | @end |
15 | @protocol NSCoding; |
16 | @protocol NSMutableCopying; |
17 | @protocol NSFastEnumeration |
18 | - (void)encodeWithCoder:(NSCoder *)aCoder; |
19 | @end |
20 | @protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; |
21 | @end |
22 | @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; |
23 | @end |
24 | @interface NSObject <NSObject> {} |
25 | + (id)alloc; |
26 | - (id)init; |
27 | - (NSString *)description; |
28 | @end |
29 | @interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> |
30 | - (NSUInteger)count; |
31 | - (id)initWithObjects:(const id [])objects count:(NSUInteger)cnt; |
32 | + (id)arrayWithObject:(id)anObject; |
33 | + (id)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt; |
34 | + (id)arrayWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1))); |
35 | - (id)initWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1))); |
36 | - (id)initWithArray:(NSArray *)array; |
37 | @end |
38 | |
39 | typedef const struct __CFAllocator * CFAllocatorRef; |
40 | extern const CFAllocatorRef kCFAllocatorDefault; |
41 | typedef double CFTimeInterval; |
42 | typedef CFTimeInterval CFAbsoluteTime; |
43 | extern CFAbsoluteTime CFAbsoluteTimeGetCurrent(void); |
44 | typedef const struct __CFDate * CFDateRef; |
45 | extern CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at); |
46 | |
47 | typedef const void* objc_objectptr_t; |
48 | __attribute__((ns_returns_retained)) id objc_retainedObject(objc_objectptr_t __attribute__((cf_consumed)) pointer); |
49 | __attribute__((ns_returns_not_retained)) id objc_unretainedObject(objc_objectptr_t pointer); |
50 | |
51 | // Test the analyzer is working at all. |
52 | void test_working() { |
53 | int *p = 0; |
54 | *p = 0xDEADBEEF; // expected-warning {{null}} |
55 | } |
56 | |
57 | // Test that in ARC mode that blocks are correctly automatically copied |
58 | // and not flagged as warnings by the analyzer. |
59 | typedef void (^Block)(void); |
60 | void testblock_bar(int x); |
61 | |
62 | Block testblock_foo(int x) { |
63 | Block b = ^{ testblock_bar(x); }; |
64 | return b; // no-warning |
65 | } |
66 | |
67 | Block testblock_baz(int x) { |
68 | return ^{ testblock_bar(x); }; // no-warning |
69 | } |
70 | |
71 | Block global_block; |
72 | |
73 | void testblock_qux(int x) { |
74 | global_block = ^{ testblock_bar(x); }; // no-warning |
75 | } |
76 | |
77 | // Test that Objective-C pointers are null initialized. |
78 | void test_nil_initialized() { |
79 | id x; |
80 | if (x == 0) |
81 | return; |
82 | int *p = 0; |
83 | *p = 0xDEADBEEF; // no-warning |
84 | } |
85 | |
86 | // Test that we don't flag leaks of Objective-C objects. |
87 | void test_alloc() { |
88 | [NSObject alloc]; // no-warning |
89 | } |
90 | |
91 | // Test that CF allocations are still caught as leaks. |
92 | void test_cf_leak() { |
93 | CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); |
94 | CFDateRef date = CFDateCreate(0, t); // expected-warning {{Potential leak}} |
95 | (void) date; |
96 | } |
97 | |
98 | // Test that 'init' methods do not try to claim ownerhip of an *unowned* allocated object |
99 | // in ARC mode. |
100 | @interface RDar9424890_A : NSObject |
101 | - (id)initWithCleaner:(int)pop mop:(NSString *)mop ; |
102 | - (RDar9424890_A *)rdar9424890:(NSString *)identifier; |
103 | @end |
104 | @interface RDar9424890_B : NSObject |
105 | @end |
106 | @implementation RDar9424890_B |
107 | - (RDar9424890_A *)obj:(RDar9424890_A *)obj { |
108 | static NSString *WhizFiz = @"WhizFiz"; |
109 | RDar9424890_A *cell = [obj rdar9424890:WhizFiz]; |
110 | if (cell == ((void*)0)) { |
111 | cell = [[RDar9424890_A alloc] initWithCleaner:0 mop:WhizFiz]; // no-warning |
112 | } |
113 | return cell; |
114 | } |
115 | @end |
116 | |
117 | // Test that dead store checking works in the prescence of "cleanups" in the AST. |
118 | void rdar9424882() { |
119 | id x = [NSObject alloc]; // expected-warning {{Value stored to 'x' during its initialization is never read}} |
120 | } |
121 | |
122 | // Test |
123 | typedef const void *CFTypeRef; |
124 | typedef const struct __CFString *CFStringRef; |
125 | |
126 | @interface NSString : NSObject |
127 | - (id) self; |
128 | @end |
129 | |
130 | CFTypeRef CFCreateSomething(); |
131 | CFStringRef CFCreateString(); |
132 | CFTypeRef CFGetSomething(); |
133 | CFStringRef CFGetString(); |
134 | |
135 | id CreateSomething(); |
136 | NSString *CreateNSString(); |
137 | |
138 | void from_cf() { |
139 | id obj1 = (__bridge_transfer id)CFCreateSomething(); // expected-warning{{never read}} |
140 | id obj2 = (__bridge_transfer NSString*)CFCreateString(); |
141 | [obj2 self]; // Add a use, to show we can use the object after it has been transferred. |
142 | id obj3 = (__bridge id)CFGetSomething(); |
143 | [obj3 self]; // Add a use, to show we can use the object after it has been bridged. |
144 | id obj4 = (__bridge NSString*)CFGetString(); // expected-warning{{never read}} |
145 | id obj5 = (__bridge id)CFCreateSomething(); // expected-warning{{never read}} expected-warning{{leak}} |
146 | id obj6 = (__bridge NSString*)CFCreateString(); // expected-warning{{never read}} expected-warning{{leak}} |
147 | } |
148 | |
149 | void to_cf(id obj) { |
150 | CFTypeRef cf1 = (__bridge_retained CFTypeRef)CreateSomething(); // expected-warning{{never read}} |
151 | CFStringRef cf2 = (__bridge_retained CFStringRef)CreateNSString(); // expected-warning{{never read}} |
152 | CFTypeRef cf3 = (__bridge CFTypeRef)CreateSomething(); // expected-warning{{never read}} |
153 | CFStringRef cf4 = (__bridge CFStringRef)CreateNSString(); // expected-warning{{never read}} |
154 | } |
155 | |
156 | void test_objc_retainedObject() { |
157 | CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); |
158 | CFDateRef date = CFDateCreate(0, t); |
159 | id x = objc_retainedObject(date); |
160 | (void) x; |
161 | } |
162 | |
163 | void test_objc_unretainedObject() { |
164 | CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); |
165 | CFDateRef date = CFDateCreate(0, t); // expected-warning {{Potential leak}} |
166 | id x = objc_unretainedObject(date); |
167 | (void) x; |
168 | } |
169 | |
170 | // Previously this resulted in a "return of stack address" warning. |
171 | id test_return() { |
172 | id x = (__bridge_transfer id) CFCreateString(); |
173 | return x; // no-warning |
174 | } |
175 | |
176 | void test_objc_arrays() { |
177 | { // CASE ONE -- OBJECT IN ARRAY CREATED DIRECTLY |
178 | NSObject *o = [[NSObject alloc] init]; |
179 | NSArray *a = [[NSArray alloc] initWithObjects:o, (void*)0]; |
180 | [a description]; |
181 | [o description]; |
182 | } |
183 | |
184 | { // CASE TWO -- OBJECT IN ARRAY CREATED BY DUPING AUTORELEASED ARRAY |
185 | NSObject *o = [[NSObject alloc] init]; |
186 | NSArray *a1 = [NSArray arrayWithObjects:o, (void*)0]; |
187 | NSArray *a2 = [[NSArray alloc] initWithArray:a1]; |
188 | [a2 description]; |
189 | [o description]; |
190 | } |
191 | |
192 | { // CASE THREE -- OBJECT IN RETAINED @[] |
193 | NSObject *o = [[NSObject alloc] init]; |
194 | NSArray *a3 = @[o]; |
195 | [a3 description]; |
196 | [o description]; |
197 | } |
198 | { |
199 | // CASE 4, verify analyzer still working. |
200 | CFCreateString(); // expected-warning {{leak}} |
201 | } |
202 | } |
203 | |
204 | // <rdar://problem/11059275> - dispatch_set_context and ARC. |
205 | __attribute__((cf_returns_retained)) CFTypeRef CFBridgingRetain(id X); |
206 | typedef void* dispatch_object_t; |
207 | void dispatch_set_context(dispatch_object_t object, const void *context); |
208 | |
209 | void rdar11059275(dispatch_object_t object) { |
210 | NSObject *o = [[NSObject alloc] init]; |
211 | dispatch_set_context(object, CFBridgingRetain(o)); // no-warning |
212 | } |
213 | void rdar11059275_positive() { |
214 | NSObject *o = [[NSObject alloc] init]; // expected-warning {{leak}} |
215 | CFBridgingRetain(o); |
216 | } |
217 | void rdar11059275_negative() { |
218 | NSObject *o = [[NSObject alloc] init]; // no-warning |
219 | (void) o; |
220 | } |
221 | |
222 | __attribute__((ns_returns_retained)) id rdar14061675_helper() { |
223 | return [[NSObject alloc] init]; |
224 | } |
225 | |
226 | id rdar14061675() { |
227 | // ARC produces an implicit cast here. We need to make sure the combination |
228 | // of that and the inlined call don't produce a spurious edge cycle. |
229 | id result = rdar14061675_helper(); |
230 | *(volatile int *)0 = 1; // expected-warning{{Dereference of null pointer}} |
231 | return result; |
232 | } |
233 | |
234 | typedef const void * CFTypeRef; |
235 | typedef const struct __CFString * CFStringRef; |
236 | typedef const struct __CFAllocator * CFAllocatorRef; |
237 | extern const CFAllocatorRef kCFAllocatorDefault; |
238 | |
239 | extern CFTypeRef CFRetain(CFTypeRef cf); |
240 | extern void CFRelease(CFTypeRef cf); |
241 | |
242 | |
243 | void check_bridge_retained_cast() { |
244 | NSString *nsStr = [[NSString alloc] init]; |
245 | CFStringRef cfStr = (__bridge_retained CFStringRef)nsStr; |
246 | CFRelease(cfStr); // no-warning |
247 | } |
248 | |
249 | @interface A; |
250 | @end |
251 | |
252 | void check_bridge_to_non_cocoa(CFStringRef s) { |
253 | A *a = (__bridge_transfer A *) s; // no-crash |
254 | } |
255 | |
256 | struct B; |
257 | |
258 | struct B * check_bridge_to_non_cf() { |
259 | NSString *s = [[NSString alloc] init]; |
260 | return (__bridge struct B*) s; |
261 | } |
262 | |