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@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
171BOOL 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
184BOOL writeToErrorNoWarning(NSError *__autoreleasing* error) {
185  *error = [NSError errorWithDomain:1]; // no-warning
186  return 0;
187}
188
189BOOL 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
208void writeIntoError(NSError **error) {
209  *error = [NSError errorWithDomain:1];
210}
211
212extern void readError(NSError *error);
213
214void 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
221void escapeErrorFromIterator(NSError *__autoreleasing* _Nonnull error, NSDictionary *a) {
222  [a enumerateKeysAndObjectsUsingBlock:^{
223     writeIntoError(error); // expected-warning{{Capture of autoreleasing out parameter}}
224  }];
225}
226
227void noWarningOnRead(NSError *__autoreleasing* error, NSDictionary *a) {
228  [a enumerateKeysAndObjectsUsingBlock:^{
229     NSError* local = *error; // no-warning
230  }];
231}
232
233void 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
244void 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
252void noWarningOnEscapeReadMethod(NSError *__autoreleasing* error,
253                                 NSDictionary *a,
254                                 ErrorCapture *capturer) {
255  [a enumerateKeysAndObjectsUsingBlock:^{
256    [capturer captureError:*error]; // no-warning
257  }];
258}
259
260void 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
268typedef void (^errBlock)(NSError *__autoreleasing *error);
269
270extern void expectError(errBlock);
271
272void 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