summaryrefslogtreecommitdiff
path: root/test/Analysis/autoreleasewritechecker_test.m
diff options
context:
space:
mode:
Diffstat (limited to 'test/Analysis/autoreleasewritechecker_test.m')
-rw-r--r--test/Analysis/autoreleasewritechecker_test.m281
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
+