diff options
Diffstat (limited to 'test/Analysis/autoreleasewritechecker_test.m')
-rw-r--r-- | test/Analysis/autoreleasewritechecker_test.m | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/test/Analysis/autoreleasewritechecker_test.m b/test/Analysis/autoreleasewritechecker_test.m new file mode 100644 index 0000000000000..b3d34b9b11fa5 --- /dev/null +++ b/test/Analysis/autoreleasewritechecker_test.m @@ -0,0 +1,281 @@ +// 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 + |