| // UNSUPPORTED: system-windows |
| // RUN: %clang_analyze_cc1 -DARC -fobjc-arc -analyzer-checker=core,osx.cocoa.AutoreleaseWrite %s -triple x86_64-darwin -fblocks -verify |
| // RUN: %clang_analyze_cc1 -DNOARC -analyzer-checker=core,osx.cocoa.AutoreleaseWrite %s -fblocks -triple x86_64-darwin -verify |
| |
| |
| typedef signed char BOOL; |
| #define YES ((BOOL)1) |
| @protocol NSObject - (BOOL)isEqual:(id)object; @end |
| @interface NSObject <NSObject> {} |
| +(id)alloc; |
| -(id)init; |
| -(id)autorelease; |
| -(id)copy; |
| -(id)retain; |
| @end |
| typedef int NSZone; |
| typedef int NSCoder; |
| typedef unsigned long NSUInteger; |
| |
| @protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end |
| @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end |
| @interface NSError : NSObject <NSCopying, NSCoding> {} |
| + (id)errorWithDomain:(int)domain; |
| @end |
| |
| typedef int dispatch_semaphore_t; |
| typedef void (^block_t)(); |
| |
| typedef enum { |
| NSEnumerationConcurrent = (1UL << 0), |
| NSEnumerationReverse = (1UL << 1) |
| } NSEnumerationOptions; |
| |
| @interface NSArray |
| - (void)enumerateObjectsUsingBlock:(block_t)block; |
| @end |
| |
| @interface NSSet |
| - (void)objectsPassingTest:(block_t)block; |
| @end |
| |
| @interface NSDictionary |
| - (void)enumerateKeysAndObjectsUsingBlock:(block_t)block; |
| @end |
| |
| @interface NSIndexSet |
| - (void)indexesPassingTest:(block_t)block; |
| - (NSUInteger)indexWithOptions:(NSEnumerationOptions)opts |
| passingTest:(BOOL (^)(NSUInteger idx, BOOL *stop))predicate; |
| @end |
| |
| typedef int group_t; |
| typedef struct dispatch_queue_s *dispatch_queue_t; |
| typedef void (^dispatch_block_t)(void); |
| extern dispatch_queue_t queue; |
| |
| void dispatch_group_async(dispatch_queue_t queue, |
| group_t group, |
| dispatch_block_t block); |
| void dispatch_async(dispatch_queue_t queue, dispatch_block_t block); |
| dispatch_semaphore_t dispatch_semaphore_create(int); |
| |
| void dispatch_semaphore_wait(dispatch_semaphore_t, int); |
| void dispatch_semaphore_signal(dispatch_semaphore_t); |
| |
| // No warnings without ARC. |
| #ifdef NOARC |
| |
| // expected-no-diagnostics |
| BOOL writeToErrorWithIterator(NSError ** error, NSArray *a) { |
| [a enumerateObjectsUsingBlock:^{ |
| *error = [NSError errorWithDomain:1]; // no-warning |
| }]; |
| return 0; |
| } |
| #endif |
| |
| #ifdef ARC |
| @interface I : NSObject |
| - (BOOL) writeToStrongErrorInBlock:(NSError *__strong *)error; |
| - (BOOL) writeToErrorInBlock:(NSError *__autoreleasing *)error; |
| - (BOOL) writeToLocalErrorInBlock:(NSError **)error; |
| - (BOOL) writeToErrorInBlockMultipleTimes:(NSError *__autoreleasing *)error; |
| - (BOOL) writeToError:(NSError *__autoreleasing *)error; |
| - (BOOL) writeToErrorWithDispatchGroup:(NSError *__autoreleasing *)error; |
| @end |
| |
| @implementation I |
| |
| - (BOOL) writeToErrorInBlock:(NSError *__autoreleasing *)error { |
| dispatch_semaphore_t sem = dispatch_semaphore_create(0l); |
| dispatch_async(queue, ^{ |
| if (error) { |
| *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}} |
| } |
| dispatch_semaphore_signal(sem); |
| }); |
| |
| dispatch_semaphore_wait(sem, 100); |
| return 0; |
| } |
| |
| - (BOOL) writeToErrorWithDispatchGroup:(NSError *__autoreleasing *)error { |
| dispatch_semaphore_t sem = dispatch_semaphore_create(0l); |
| dispatch_group_async(queue, 0, ^{ |
| if (error) { |
| *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}} |
| } |
| dispatch_semaphore_signal(sem); |
| }); |
| |
| dispatch_semaphore_wait(sem, 100); |
| return 0; |
| } |
| |
| - (BOOL) writeToLocalErrorInBlock:(NSError *__autoreleasing *)error { |
| dispatch_semaphore_t sem = dispatch_semaphore_create(0l); |
| dispatch_async(queue, ^{ |
| NSError* error2; |
| NSError*__strong* error3 = &error2; |
| if (error) { |
| *error3 = [NSError errorWithDomain:1]; // no-warning |
| } |
| dispatch_semaphore_signal(sem); |
| }); |
| |
| dispatch_semaphore_wait(sem, 100); |
| return 0; |
| } |
| |
| - (BOOL) writeToStrongErrorInBlock:(NSError *__strong *)error { |
| dispatch_semaphore_t sem = dispatch_semaphore_create(0l); |
| dispatch_async(queue, ^{ |
| if (error) { |
| *error = [NSError errorWithDomain:2]; // no-warning |
| } |
| dispatch_semaphore_signal(sem); |
| }); |
| |
| dispatch_semaphore_wait(sem, 100); |
| return 0; |
| } |
| |
| - (BOOL) writeToErrorInBlockMultipleTimes:(NSError *__autoreleasing *)error { |
| dispatch_semaphore_t sem = dispatch_semaphore_create(0l); |
| dispatch_async(queue, ^{ |
| if (error) { |
| *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}} |
| } |
| dispatch_semaphore_signal(sem); |
| }); |
| dispatch_async(queue, ^{ |
| if (error) { |
| *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}} |
| *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}} |
| } |
| dispatch_semaphore_signal(sem); |
| }); |
| *error = [NSError errorWithDomain:1]; // no-warning |
| |
| dispatch_semaphore_wait(sem, 100); |
| return 0; |
| } |
| |
| - (BOOL) writeToError:(NSError *__autoreleasing *)error { |
| *error = [NSError errorWithDomain:1]; // no-warning |
| return 0; |
| } |
| @end |
| |
| BOOL writeToErrorInBlockFromCFunc(NSError *__autoreleasing* error) { |
| dispatch_semaphore_t sem = dispatch_semaphore_create(0l); |
| dispatch_async(queue, ^{ |
| if (error) { |
| *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}} |
| } |
| dispatch_semaphore_signal(sem); |
| }); |
| |
| dispatch_semaphore_wait(sem, 100); |
| return 0; |
| } |
| |
| BOOL writeToErrorNoWarning(NSError *__autoreleasing* error) { |
| *error = [NSError errorWithDomain:1]; // no-warning |
| return 0; |
| } |
| |
| BOOL writeToErrorWithIterator(NSError *__autoreleasing* error, NSArray *a, NSSet *s, NSDictionary *d, NSIndexSet *i) { [a enumerateObjectsUsingBlock:^{ |
| *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}} |
| }]; |
| [d enumerateKeysAndObjectsUsingBlock:^{ |
| *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}} |
| }]; |
| [s objectsPassingTest:^{ |
| *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}} |
| }]; |
| [i indexesPassingTest:^{ |
| *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}} |
| }]; |
| [i indexWithOptions: NSEnumerationReverse passingTest:^(NSUInteger idx, BOOL *stop) { |
| *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}} |
| return YES; |
| }]; |
| return 0; |
| } |
| |
| void writeIntoError(NSError **error) { |
| *error = [NSError errorWithDomain:1]; |
| } |
| |
| extern void readError(NSError *error); |
| |
| void writeToErrorWithIteratorNonnull(NSError *__autoreleasing* _Nonnull error, NSDictionary *a) { |
| [a enumerateKeysAndObjectsUsingBlock:^{ |
| *error = [NSError errorWithDomain:1]; // expected-warning{{Write to autoreleasing out parameter}} |
| }]; |
| } |
| |
| |
| void escapeErrorFromIterator(NSError *__autoreleasing* _Nonnull error, NSDictionary *a) { |
| [a enumerateKeysAndObjectsUsingBlock:^{ |
| writeIntoError(error); // expected-warning{{Capture of autoreleasing out parameter}} |
| }]; |
| } |
| |
| void noWarningOnRead(NSError *__autoreleasing* error, NSDictionary *a) { |
| [a enumerateKeysAndObjectsUsingBlock:^{ |
| NSError* local = *error; // no-warning |
| }]; |
| } |
| |
| void noWarningOnEscapeRead(NSError *__autoreleasing* error, NSDictionary *a) { |
| [a enumerateKeysAndObjectsUsingBlock:^{ |
| readError(*error); // no-warning |
| }]; |
| } |
| |
| @interface ErrorCapture |
| - (void) captureErrorOut:(NSError**) error; |
| - (void) captureError:(NSError*) error; |
| @end |
| |
| void escapeErrorFromIteratorMethod(NSError *__autoreleasing* _Nonnull error, |
| NSDictionary *a, |
| ErrorCapture *capturer) { |
| [a enumerateKeysAndObjectsUsingBlock:^{ |
| [capturer captureErrorOut:error]; // expected-warning{{Capture of autoreleasing out parameter}} |
| }]; |
| } |
| |
| void noWarningOnEscapeReadMethod(NSError *__autoreleasing* error, |
| NSDictionary *a, |
| ErrorCapture *capturer) { |
| [a enumerateKeysAndObjectsUsingBlock:^{ |
| [capturer captureError:*error]; // no-warning |
| }]; |
| } |
| |
| void multipleErrors(NSError *__autoreleasing* error, NSDictionary *a) { |
| [a enumerateKeysAndObjectsUsingBlock:^{ |
| writeIntoError(error); // expected-warning{{Capture of autoreleasing out parameter}} |
| *error = [NSError errorWithDomain:1]; // expected-warning{{Write to autoreleasing out parameter}} |
| writeIntoError(error); // expected-warning{{Capture of autoreleasing out parameter}} |
| }]; |
| } |
| |
| typedef void (^errBlock)(NSError *__autoreleasing *error); |
| |
| extern void expectError(errBlock); |
| |
| void captureAutoreleasingVarFromBlock(NSDictionary *dict) { |
| expectError(^(NSError *__autoreleasing *err) { |
| [dict enumerateKeysAndObjectsUsingBlock:^{ |
| writeIntoError(err); // expected-warning{{Capture of autoreleasing out parameter 'err'}} |
| }]; |
| }); |
| } |
| |
| #endif |
| |