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
6typedef 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
16typedef int NSZone;
17typedef int NSCoder;
18typedef 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
26typedef int dispatch_semaphore_t;
27typedef void (^block_t)();
28
29typedef 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
52typedef int group_t;
53typedef struct dispatch_queue_s *dispatch_queue_t;
54typedef void (^dispatch_block_t)(void);
55extern dispatch_queue_t queue;
56
57void dispatch_group_async(dispatch_queue_t queue,
58                          group_t group,
59                          dispatch_block_t block);
60void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
61dispatch_semaphore_t dispatch_semaphore_create(int);
62
63void dispatch_semaphore_wait(dispatch_semaphore_t, int);
64void dispatch_semaphore_signal(dispatch_semaphore_t);
65
66// No warnings without ARC.
67#ifdef NOARC
68
69// expected-no-diagnostics
70BOOL 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- (BOOL)writeToErrorInAutoreleasePool:(NSError *__autoreleasing *)error;
87- (BOOL)writeToStrongErrorInAutoreleasePool:(NSError *__strong *)error;
88- (BOOL)writeToLocalErrorInAutoreleasePool:(NSError *__autoreleasing *)error;
89- (BOOL)writeToErrorInAutoreleasePoolMultipleTimes:(NSError *__autoreleasing *)error;
90@end
91
92@implementation I
93
94- (BOOL) writeToErrorInBlock:(NSError *__autoreleasing *)error {
95    dispatch_semaphore_t sem = dispatch_semaphore_create(0l);
96    dispatch_async(queue, ^{
97        if (error) {
98            *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}}
99        }
100        dispatch_semaphore_signal(sem);
101    });
102
103    dispatch_semaphore_wait(sem, 100);
104    return 0;
105}
106
107- (BOOL) writeToErrorWithDispatchGroup:(NSError *__autoreleasing *)error {
108    dispatch_semaphore_t sem = dispatch_semaphore_create(0l);
109    dispatch_group_async(queue, 0, ^{
110        if (error) {
111            *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}}
112        }
113        dispatch_semaphore_signal(sem);
114    });
115
116    dispatch_semaphore_wait(sem, 100);
117    return 0;
118}
119
120- (BOOL) writeToLocalErrorInBlock:(NSError *__autoreleasing *)error {
121    dispatch_semaphore_t sem = dispatch_semaphore_create(0l);
122    dispatch_async(queue, ^{
123        NSError* error2;
124        NSError*__strong* error3 = &error2;
125        if (error) {
126            *error3 = [NSError errorWithDomain:1]; // no-warning
127        }
128        dispatch_semaphore_signal(sem);
129    });
130
131    dispatch_semaphore_wait(sem, 100);
132    return 0;
133}
134
135- (BOOL) writeToStrongErrorInBlock:(NSError *__strong *)error {
136    dispatch_semaphore_t sem = dispatch_semaphore_create(0l);
137    dispatch_async(queue, ^{
138        if (error) {
139            *error = [NSError errorWithDomain:2]; // no-warning
140        }
141        dispatch_semaphore_signal(sem);
142    });
143
144    dispatch_semaphore_wait(sem, 100);
145    return 0;
146}
147
148- (BOOL) writeToErrorInBlockMultipleTimes:(NSError *__autoreleasing *)error {
149    dispatch_semaphore_t sem = dispatch_semaphore_create(0l);
150    dispatch_async(queue, ^{
151        if (error) {
152            *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}}
153        }
154        dispatch_semaphore_signal(sem);
155    });
156    dispatch_async(queue, ^{
157        if (error) {
158            *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}}
159            *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}}
160        }
161        dispatch_semaphore_signal(sem);
162    });
163    *error = [NSError errorWithDomain:1]; // no-warning
164
165    dispatch_semaphore_wait(sem, 100);
166    return 0;
167}
168
169- (BOOL)writeToErrorInAutoreleasePool:(NSError *__autoreleasing *)error {
170  @autoreleasepool {
171    if (error) {
172      *error = [NSError errorWithDomain:1]; // expected-warning{{Write to autoreleasing out parameter inside locally-scoped autorelease pool; consider writing first to a strong local variable declared outside of the autorelease pool}}
173    }
174  }
175
176  return 0;
177}
178
179- (BOOL)writeToStrongErrorInAutoreleasePool:(NSError *__strong *)error {
180  @autoreleasepool {
181    if (error) {
182      *error = [NSError errorWithDomain:1]; // no-warning
183    }
184  }
185
186  return 0;
187}
188
189- (BOOL)writeToLocalErrorInAutoreleasePool:(NSError *__autoreleasing *)error {
190  NSError *localError;
191  @autoreleasepool {
192    localError = [NSError errorWithDomain:1]; // no-warning
193  }
194
195  if (error) {
196    *error = localError; // no-warning
197  }
198
199  return 0;
200}
201
202- (BOOL)writeToErrorInAutoreleasePoolMultipleTimes:(NSError *__autoreleasing *)error {
203  @autoreleasepool {
204    if (error) {
205      *error = [NSError errorWithDomain:1]; // expected-warning{{Write to autoreleasing out parameter inside locally-scoped autorelease pool; consider writing first to a strong local variable declared outside of the autorelease pool}}
206    }
207  }
208  if (error) {
209    *error = [NSError errorWithDomain:1]; // no-warning
210  }
211  @autoreleasepool {
212    if (error) {
213      *error = [NSError errorWithDomain:1]; // expected-warning{{Write to autoreleasing out parameter inside locally-scoped autorelease pool; consider writing first to a strong local variable declared outside of the autorelease pool}}
214      *error = [NSError errorWithDomain:1]; // expected-warning{{Write to autoreleasing out parameter inside locally-scoped autorelease pool; consider writing first to a strong local variable declared outside of the autorelease pool}}
215    }
216  }
217
218  return 0;
219}
220
221- (BOOL) writeToError:(NSError *__autoreleasing *)error {
222    *error = [NSError errorWithDomain:1]; // no-warning
223    return 0;
224}
225@end
226
227BOOL writeToErrorInBlockFromCFunc(NSError *__autoreleasing* error) {
228    dispatch_semaphore_t sem = dispatch_semaphore_create(0l);
229    dispatch_async(queue, ^{
230        if (error) {
231            *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}}
232        }
233        dispatch_semaphore_signal(sem);
234    });
235
236    dispatch_semaphore_wait(sem, 100);
237  return 0;
238}
239
240BOOL writeIntoErrorInAutoreleasePoolFromCFunc(NSError *__autoreleasing *error) {
241  @autoreleasepool {
242    if (error) {
243      *error = [NSError errorWithDomain:1]; // expected-warning{{Write to autoreleasing out parameter inside locally-scoped autorelease pool; consider writing first to a strong local variable declared outside of the autorelease pool}}
244    }
245  }
246  return 0;
247}
248
249BOOL writeToErrorNoWarning(NSError *__autoreleasing* error) {
250  *error = [NSError errorWithDomain:1]; // no-warning
251  return 0;
252}
253
254BOOL writeToErrorWithIterator(NSError *__autoreleasing* error, NSArray *a, NSSet *s, NSDictionary *d, NSIndexSet *i) { [a enumerateObjectsUsingBlock:^{
255    *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}}
256    }];
257  [d enumerateKeysAndObjectsUsingBlock:^{
258    *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}}
259    }];
260  [s objectsPassingTest:^{
261    *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}}
262    }];
263  [i indexesPassingTest:^{
264    *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}}
265    }];
266  [i indexWithOptions: NSEnumerationReverse passingTest:^(NSUInteger idx, BOOL *stop) {
267    *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}}
268    return YES;
269    }];
270  return 0;
271}
272
273void writeIntoError(NSError **error) {
274  *error = [NSError errorWithDomain:1];
275}
276
277extern void readError(NSError *error);
278
279void writeToErrorWithIteratorNonnull(NSError *__autoreleasing* _Nonnull error, NSDictionary *a) {
280  [a enumerateKeysAndObjectsUsingBlock:^{
281     *error = [NSError errorWithDomain:1]; // expected-warning{{Write to autoreleasing out parameter}}
282  }];
283}
284
285
286void escapeErrorFromIterator(NSError *__autoreleasing* _Nonnull error, NSDictionary *a) {
287  [a enumerateKeysAndObjectsUsingBlock:^{
288     writeIntoError(error); // expected-warning{{Capture of autoreleasing out parameter}}
289  }];
290}
291
292void noWarningOnRead(NSError *__autoreleasing* error, NSDictionary *a) {
293  [a enumerateKeysAndObjectsUsingBlock:^{
294     NSError* local = *error; // no-warning
295  }];
296}
297
298void noWarningOnEscapeRead(NSError *__autoreleasing* error, NSDictionary *a) {
299  [a enumerateKeysAndObjectsUsingBlock:^{
300     readError(*error); // no-warning
301  }];
302}
303
304@interface ErrorCapture
305- (void) captureErrorOut:(NSError**) error;
306- (void) captureError:(NSError*) error;
307@end
308
309void escapeErrorFromIteratorMethod(NSError *__autoreleasing* _Nonnull error,
310                                   NSDictionary *a,
311                                   ErrorCapture *capturer) {
312  [a enumerateKeysAndObjectsUsingBlock:^{
313      [capturer captureErrorOut:error]; // expected-warning{{Capture of autoreleasing out parameter}}
314  }];
315}
316
317void noWarningOnEscapeReadMethod(NSError *__autoreleasing* error,
318                                 NSDictionary *a,
319                                 ErrorCapture *capturer) {
320  [a enumerateKeysAndObjectsUsingBlock:^{
321    [capturer captureError:*error]; // no-warning
322  }];
323}
324
325void multipleErrors(NSError *__autoreleasing* error, NSDictionary *a) {
326  [a enumerateKeysAndObjectsUsingBlock:^{
327     writeIntoError(error); // expected-warning{{Capture of autoreleasing out parameter}}
328     *error = [NSError errorWithDomain:1]; // expected-warning{{Write to autoreleasing out parameter}}
329     writeIntoError(error); // expected-warning{{Capture of autoreleasing out parameter}}
330  }];
331}
332
333typedef void (^errBlock)(NSError *__autoreleasing *error);
334
335extern void expectError(errBlock);
336
337void captureAutoreleasingVarFromBlock(NSDictionary *dict) {
338  expectError(^(NSError *__autoreleasing *err) {
339    [dict enumerateKeysAndObjectsUsingBlock:^{
340      writeIntoError(err); // expected-warning{{Capture of autoreleasing out parameter 'err'}}
341    }];
342  });
343}
344
345#endif
346
347