1 | // UNSUPPORTED: system-windows |
2 | // RUN: %clang_analyze_cc1 -DARC -fobjc-arc -analyzer-checker=core,osx.cocoa.AutoreleaseWrite %s -triple x86_64-darwin -fblocks -verify |
3 | // RUN: %clang_analyze_cc1 -DNOARC -analyzer-checker=core,osx.cocoa.AutoreleaseWrite %s -fblocks -triple x86_64-darwin -verify |
4 | |
5 | |
6 | typedef signed char BOOL; |
7 | #define YES ((BOOL)1) |
8 | @protocol NSObject - (BOOL)isEqual:(id)object; @end |
9 | @interface NSObject <NSObject> {} |
10 | +(id)alloc; |
11 | -(id)init; |
12 | -(id)autorelease; |
13 | -(id)copy; |
14 | -(id)retain; |
15 | @end |
16 | typedef int NSZone; |
17 | typedef int NSCoder; |
18 | typedef unsigned long NSUInteger; |
19 | |
20 | @protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end |
21 | @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end |
22 | @interface NSError : NSObject <NSCopying, NSCoding> {} |
23 | + (id)errorWithDomain:(int)domain; |
24 | @end |
25 | |
26 | typedef int dispatch_semaphore_t; |
27 | typedef void (^block_t)(); |
28 | |
29 | typedef enum { |
30 | NSEnumerationConcurrent = (1UL << 0), |
31 | NSEnumerationReverse = (1UL << 1) |
32 | } NSEnumerationOptions; |
33 | |
34 | @interface NSArray |
35 | - (void)enumerateObjectsUsingBlock:(block_t)block; |
36 | @end |
37 | |
38 | @interface NSSet |
39 | - (void)objectsPassingTest:(block_t)block; |
40 | @end |
41 | |
42 | @interface NSDictionary |
43 | - (void)enumerateKeysAndObjectsUsingBlock:(block_t)block; |
44 | @end |
45 | |
46 | @interface NSIndexSet |
47 | - (void)indexesPassingTest:(block_t)block; |
48 | - (NSUInteger)indexWithOptions:(NSEnumerationOptions)opts |
49 | passingTest:(BOOL (^)(NSUInteger idx, BOOL *stop))predicate; |
50 | @end |
51 | |
52 | typedef int group_t; |
53 | typedef struct dispatch_queue_s *dispatch_queue_t; |
54 | typedef void (^dispatch_block_t)(void); |
55 | extern dispatch_queue_t queue; |
56 | |
57 | void dispatch_group_async(dispatch_queue_t queue, |
58 | group_t group, |
59 | dispatch_block_t block); |
60 | void dispatch_async(dispatch_queue_t queue, dispatch_block_t block); |
61 | dispatch_semaphore_t dispatch_semaphore_create(int); |
62 | |
63 | void dispatch_semaphore_wait(dispatch_semaphore_t, int); |
64 | void dispatch_semaphore_signal(dispatch_semaphore_t); |
65 | |
66 | // No warnings without ARC. |
67 | #ifdef NOARC |
68 | |
69 | // expected-no-diagnostics |
70 | BOOL writeToErrorWithIterator(NSError ** error, NSArray *a) { |
71 | [a enumerateObjectsUsingBlock:^{ |
72 | *error = [NSError errorWithDomain:1]; // no-warning |
73 | }]; |
74 | return 0; |
75 | } |
76 | #endif |
77 | |
78 | #ifdef ARC |
79 | @interface I : NSObject |
80 | - (BOOL) writeToStrongErrorInBlock:(NSError *__strong *)error; |
81 | - (BOOL) writeToErrorInBlock:(NSError *__autoreleasing *)error; |
82 | - (BOOL) writeToLocalErrorInBlock:(NSError **)error; |
83 | - (BOOL) writeToErrorInBlockMultipleTimes:(NSError *__autoreleasing *)error; |
84 | - (BOOL) writeToError:(NSError *__autoreleasing *)error; |
85 | - (BOOL) writeToErrorWithDispatchGroup:(NSError *__autoreleasing *)error; |
86 | @end |
87 | |
88 | @implementation I |
89 | |
90 | - (BOOL) writeToErrorInBlock:(NSError *__autoreleasing *)error { |
91 | dispatch_semaphore_t sem = dispatch_semaphore_create(0l); |
92 | dispatch_async(queue, ^{ |
93 | if (error) { |
94 | *error = [NSError errorWithDomain:1]; // expected-warning{{Write to autoreleasing out parameter inside autorelease pool that may exit before method returns; consider writing first to a strong local variable declared outside of the block}} |
95 | } |
96 | dispatch_semaphore_signal(sem); |
97 | }); |
98 | |
99 | dispatch_semaphore_wait(sem, 100); |
100 | return 0; |
101 | } |
102 | |
103 | - (BOOL) writeToErrorWithDispatchGroup:(NSError *__autoreleasing *)error { |
104 | dispatch_semaphore_t sem = dispatch_semaphore_create(0l); |
105 | dispatch_group_async(queue, 0, ^{ |
106 | if (error) { |
107 | *error = [NSError errorWithDomain:1]; // expected-warning{{Write to autoreleasing out parameter inside autorelease pool that may exit before method returns; consider writing first to a strong local variable declared outside of the block}} |
108 | } |
109 | dispatch_semaphore_signal(sem); |
110 | }); |
111 | |
112 | dispatch_semaphore_wait(sem, 100); |
113 | return 0; |
114 | } |
115 | |
116 | - (BOOL) writeToLocalErrorInBlock:(NSError *__autoreleasing *)error { |
117 | dispatch_semaphore_t sem = dispatch_semaphore_create(0l); |
118 | dispatch_async(queue, ^{ |
119 | NSError* error2; |
120 | NSError*__strong* error3 = &error2; |
121 | if (error) { |
122 | *error3 = [NSError errorWithDomain:1]; // no-warning |
123 | } |
124 | dispatch_semaphore_signal(sem); |
125 | }); |
126 | |
127 | dispatch_semaphore_wait(sem, 100); |
128 | return 0; |
129 | } |
130 | |
131 | - (BOOL) writeToStrongErrorInBlock:(NSError *__strong *)error { |
132 | dispatch_semaphore_t sem = dispatch_semaphore_create(0l); |
133 | dispatch_async(queue, ^{ |
134 | if (error) { |
135 | *error = [NSError errorWithDomain:2]; // no-warning |
136 | } |
137 | dispatch_semaphore_signal(sem); |
138 | }); |
139 | |
140 | dispatch_semaphore_wait(sem, 100); |
141 | return 0; |
142 | } |
143 | |
144 | - (BOOL) writeToErrorInBlockMultipleTimes:(NSError *__autoreleasing *)error { |
145 | dispatch_semaphore_t sem = dispatch_semaphore_create(0l); |
146 | dispatch_async(queue, ^{ |
147 | if (error) { |
148 | *error = [NSError errorWithDomain:1]; // expected-warning{{Write to autoreleasing out parameter inside autorelease pool that may exit before method returns; consider writing first to a strong local variable declared outside of the block}} |
149 | } |
150 | dispatch_semaphore_signal(sem); |
151 | }); |
152 | dispatch_async(queue, ^{ |
153 | if (error) { |
154 | *error = [NSError errorWithDomain:1]; // expected-warning{{Write to autoreleasing out parameter inside autorelease pool that may exit before method returns; consider writing first to a strong local variable declared outside of the block}} |
155 | *error = [NSError errorWithDomain:1]; // expected-warning{{Write to autoreleasing out parameter inside autorelease pool that may exit before method returns; consider writing first to a strong local variable declared outside of the block}} |
156 | } |
157 | dispatch_semaphore_signal(sem); |
158 | }); |
159 | *error = [NSError errorWithDomain:1]; // no-warning |
160 | |
161 | dispatch_semaphore_wait(sem, 100); |
162 | return 0; |
163 | } |
164 | |
165 | - (BOOL) writeToError:(NSError *__autoreleasing *)error { |
166 | *error = [NSError errorWithDomain:1]; // no-warning |
167 | return 0; |
168 | } |
169 | @end |
170 | |
171 | BOOL writeToErrorInBlockFromCFunc(NSError *__autoreleasing* error) { |
172 | dispatch_semaphore_t sem = dispatch_semaphore_create(0l); |
173 | dispatch_async(queue, ^{ |
174 | if (error) { |
175 | *error = [NSError errorWithDomain:1]; // expected-warning{{Write to autoreleasing out parameter inside autorelease pool that may exit before function returns; consider writing first to a strong local variable declared outside of the block}} |
176 | } |
177 | dispatch_semaphore_signal(sem); |
178 | }); |
179 | |
180 | dispatch_semaphore_wait(sem, 100); |
181 | return 0; |
182 | } |
183 | |
184 | BOOL writeToErrorNoWarning(NSError *__autoreleasing* error) { |
185 | *error = [NSError errorWithDomain:1]; // no-warning |
186 | return 0; |
187 | } |
188 | |
189 | BOOL writeToErrorWithIterator(NSError *__autoreleasing* error, NSArray *a, NSSet *s, NSDictionary *d, NSIndexSet *i) { [a enumerateObjectsUsingBlock:^{ |
190 | *error = [NSError errorWithDomain:1]; // expected-warning{{Write to autoreleasing out parameter inside autorelease pool that may exit before function returns; consider writing first to a strong local variable declared outside of the block}} |
191 | }]; |
192 | [d enumerateKeysAndObjectsUsingBlock:^{ |
193 | *error = [NSError errorWithDomain:1]; // expected-warning{{Write to autoreleasing out parameter inside autorelease pool that may exit before function returns; consider writing first to a strong local variable declared outside of the block}} |
194 | }]; |
195 | [s objectsPassingTest:^{ |
196 | *error = [NSError errorWithDomain:1]; // expected-warning{{Write to autoreleasing out parameter inside autorelease pool that may exit before function returns; consider writing first to a strong local variable declared outside of the block}} |
197 | }]; |
198 | [i indexesPassingTest:^{ |
199 | *error = [NSError errorWithDomain:1]; // expected-warning{{Write to autoreleasing out parameter inside autorelease pool that may exit before function returns; consider writing first to a strong local variable declared outside of the block}} |
200 | }]; |
201 | [i indexWithOptions: NSEnumerationReverse passingTest:^(NSUInteger idx, BOOL *stop) { |
202 | *error = [NSError errorWithDomain:1]; // expected-warning{{Write to autoreleasing out parameter inside autorelease pool that may exit before function returns; consider writing first to a strong local variable declared outside of the block}} |
203 | return YES; |
204 | }]; |
205 | return 0; |
206 | } |
207 | |
208 | void writeIntoError(NSError **error) { |
209 | *error = [NSError errorWithDomain:1]; |
210 | } |
211 | |
212 | extern void readError(NSError *error); |
213 | |
214 | void writeToErrorWithIteratorNonnull(NSError *__autoreleasing* _Nonnull error, NSDictionary *a) { |
215 | [a enumerateKeysAndObjectsUsingBlock:^{ |
216 | *error = [NSError errorWithDomain:1]; // expected-warning{{Write to autoreleasing out parameter}} |
217 | }]; |
218 | } |
219 | |
220 | |
221 | void escapeErrorFromIterator(NSError *__autoreleasing* _Nonnull error, NSDictionary *a) { |
222 | [a enumerateKeysAndObjectsUsingBlock:^{ |
223 | writeIntoError(error); // expected-warning{{Capture of autoreleasing out parameter}} |
224 | }]; |
225 | } |
226 | |
227 | void noWarningOnRead(NSError *__autoreleasing* error, NSDictionary *a) { |
228 | [a enumerateKeysAndObjectsUsingBlock:^{ |
229 | NSError* local = *error; // no-warning |
230 | }]; |
231 | } |
232 | |
233 | void noWarningOnEscapeRead(NSError *__autoreleasing* error, NSDictionary *a) { |
234 | [a enumerateKeysAndObjectsUsingBlock:^{ |
235 | readError(*error); // no-warning |
236 | }]; |
237 | } |
238 | |
239 | @interface ErrorCapture |
240 | - (void) captureErrorOut:(NSError**) error; |
241 | - (void) captureError:(NSError*) error; |
242 | @end |
243 | |
244 | void escapeErrorFromIteratorMethod(NSError *__autoreleasing* _Nonnull error, |
245 | NSDictionary *a, |
246 | ErrorCapture *capturer) { |
247 | [a enumerateKeysAndObjectsUsingBlock:^{ |
248 | [capturer captureErrorOut:error]; // expected-warning{{Capture of autoreleasing out parameter}} |
249 | }]; |
250 | } |
251 | |
252 | void noWarningOnEscapeReadMethod(NSError *__autoreleasing* error, |
253 | NSDictionary *a, |
254 | ErrorCapture *capturer) { |
255 | [a enumerateKeysAndObjectsUsingBlock:^{ |
256 | [capturer captureError:*error]; // no-warning |
257 | }]; |
258 | } |
259 | |
260 | void multipleErrors(NSError *__autoreleasing* error, NSDictionary *a) { |
261 | [a enumerateKeysAndObjectsUsingBlock:^{ |
262 | writeIntoError(error); // expected-warning{{Capture of autoreleasing out parameter}} |
263 | *error = [NSError errorWithDomain:1]; // expected-warning{{Write to autoreleasing out parameter}} |
264 | writeIntoError(error); // expected-warning{{Capture of autoreleasing out parameter}} |
265 | }]; |
266 | } |
267 | |
268 | typedef void (^errBlock)(NSError *__autoreleasing *error); |
269 | |
270 | extern void expectError(errBlock); |
271 | |
272 | void captureAutoreleasingVarFromBlock(NSDictionary *dict) { |
273 | expectError(^(NSError *__autoreleasing *err) { |
274 | [dict enumerateKeysAndObjectsUsingBlock:^{ |
275 | writeIntoError(err); // expected-warning{{Capture of autoreleasing out parameter 'err'}} |
276 | }]; |
277 | }); |
278 | } |
279 | |
280 | #endif |
281 | |
282 | |