John McCall | d1e40d5 | 2011-10-02 01:16:38 +0000 | [diff] [blame] | 1 | // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,deadcode -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks -fobjc-arc %s |
John McCall | f85e193 | 2011-06-15 23:02:42 +0000 | [diff] [blame] | 2 | |
| 3 | typedef signed char BOOL; |
| 4 | typedef struct _NSZone NSZone; |
| 5 | @class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; |
Ted Kremenek | 1a45a5f | 2012-03-06 20:06:12 +0000 | [diff] [blame] | 6 | typedef unsigned long NSUInteger; |
John McCall | f85e193 | 2011-06-15 23:02:42 +0000 | [diff] [blame] | 7 | |
| 8 | @protocol NSObject |
| 9 | - (BOOL)isEqual:(id)object; |
| 10 | @end |
| 11 | @protocol NSCopying |
| 12 | - (id)copyWithZone:(NSZone *)zone; |
| 13 | @end |
Ted Kremenek | 1a45a5f | 2012-03-06 20:06:12 +0000 | [diff] [blame] | 14 | @protocol NSCoding; |
| 15 | @protocol NSMutableCopying; |
| 16 | @protocol NSFastEnumeration |
John McCall | f85e193 | 2011-06-15 23:02:42 +0000 | [diff] [blame] | 17 | - (void)encodeWithCoder:(NSCoder *)aCoder; |
| 18 | @end |
Ted Kremenek | 1a45a5f | 2012-03-06 20:06:12 +0000 | [diff] [blame] | 19 | @protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; |
| 20 | @end |
| 21 | @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; |
| 22 | @end |
John McCall | f85e193 | 2011-06-15 23:02:42 +0000 | [diff] [blame] | 23 | @interface NSObject <NSObject> {} |
| 24 | + (id)alloc; |
Ted Kremenek | 1a45a5f | 2012-03-06 20:06:12 +0000 | [diff] [blame] | 25 | - (id)init; |
| 26 | - (NSString *)description; |
John McCall | f85e193 | 2011-06-15 23:02:42 +0000 | [diff] [blame] | 27 | @end |
Ted Kremenek | 1a45a5f | 2012-03-06 20:06:12 +0000 | [diff] [blame] | 28 | @interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> |
| 29 | - (NSUInteger)count; |
| 30 | - (id)initWithObjects:(const id [])objects count:(NSUInteger)cnt; |
| 31 | + (id)arrayWithObject:(id)anObject; |
| 32 | + (id)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt; |
| 33 | + (id)arrayWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1))); |
| 34 | - (id)initWithObjects:(id)firstObj, ... __attribute__((sentinel(0,1))); |
| 35 | - (id)initWithArray:(NSArray *)array; |
| 36 | @end |
| 37 | |
John McCall | f85e193 | 2011-06-15 23:02:42 +0000 | [diff] [blame] | 38 | typedef const struct __CFAllocator * CFAllocatorRef; |
| 39 | extern const CFAllocatorRef kCFAllocatorDefault; |
| 40 | typedef double CFTimeInterval; |
| 41 | typedef CFTimeInterval CFAbsoluteTime; |
| 42 | extern CFAbsoluteTime CFAbsoluteTimeGetCurrent(void); |
| 43 | typedef const struct __CFDate * CFDateRef; |
| 44 | extern CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at); |
| 45 | |
| 46 | typedef const void* objc_objectptr_t; |
| 47 | __attribute__((ns_returns_retained)) id objc_retainedObject(objc_objectptr_t __attribute__((cf_consumed)) pointer); |
| 48 | __attribute__((ns_returns_not_retained)) id objc_unretainedObject(objc_objectptr_t pointer); |
| 49 | |
| 50 | // Test the analyzer is working at all. |
| 51 | void test_working() { |
| 52 | int *p = 0; |
| 53 | *p = 0xDEADBEEF; // expected-warning {{null}} |
| 54 | } |
| 55 | |
| 56 | // Test that in ARC mode that blocks are correctly automatically copied |
| 57 | // and not flagged as warnings by the analyzer. |
| 58 | typedef void (^Block)(void); |
| 59 | void testblock_bar(int x); |
| 60 | |
| 61 | Block testblock_foo(int x) { |
| 62 | Block b = ^{ testblock_bar(x); }; |
| 63 | return b; // no-warning |
| 64 | } |
| 65 | |
| 66 | Block testblock_baz(int x) { |
| 67 | return ^{ testblock_bar(x); }; // no-warning |
| 68 | } |
| 69 | |
| 70 | Block global_block; |
| 71 | |
| 72 | void testblock_qux(int x) { |
| 73 | global_block = ^{ testblock_bar(x); }; // no-warning |
| 74 | } |
| 75 | |
| 76 | // Test that Objective-C pointers are null initialized. |
| 77 | void test_nil_initialized() { |
| 78 | id x; |
| 79 | if (x == 0) |
| 80 | return; |
| 81 | int *p = 0; |
| 82 | *p = 0xDEADBEEF; // no-warning |
| 83 | } |
| 84 | |
| 85 | // Test that we don't flag leaks of Objective-C objects. |
| 86 | void test_alloc() { |
| 87 | [NSObject alloc]; // no-warning |
| 88 | } |
| 89 | |
| 90 | // Test that CF allocations are still caught as leaks. |
| 91 | void test_cf_leak() { |
| 92 | CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); |
| 93 | CFDateRef date = CFDateCreate(0, t); // expected-warning {{Potential leak}} |
| 94 | (void) date; |
| 95 | } |
| 96 | |
| 97 | // Test that 'init' methods do not try to claim ownerhip of an *unowned* allocated object |
| 98 | // in ARC mode. |
| 99 | @interface RDar9424890_A : NSObject |
| 100 | - (id)initWithCleaner:(int)pop mop:(NSString *)mop ; |
| 101 | - (RDar9424890_A *)rdar9424890:(NSString *)identifier; |
| 102 | @end |
| 103 | @interface RDar9424890_B : NSObject |
| 104 | @end |
| 105 | @implementation RDar9424890_B |
| 106 | - (RDar9424890_A *)obj:(RDar9424890_A *)obj { |
| 107 | static NSString *WhizFiz = @"WhizFiz"; |
| 108 | RDar9424890_A *cell = [obj rdar9424890:WhizFiz]; |
| 109 | if (cell == ((void*)0)) { |
| 110 | cell = [[RDar9424890_A alloc] initWithCleaner:0 mop:WhizFiz]; // no-warning |
| 111 | } |
| 112 | return cell; |
| 113 | } |
| 114 | @end |
| 115 | |
| 116 | // Test that dead store checking works in the prescence of "cleanups" in the AST. |
| 117 | void rdar9424882() { |
| 118 | id x = [NSObject alloc]; // expected-warning {{Value stored to 'x' during its initialization is never read}} |
| 119 | } |
| 120 | |
| 121 | // Test |
| 122 | typedef const void *CFTypeRef; |
| 123 | typedef const struct __CFString *CFStringRef; |
| 124 | |
| 125 | @interface NSString |
| 126 | - (id) self; |
| 127 | @end |
| 128 | |
| 129 | CFTypeRef CFCreateSomething(); |
| 130 | CFStringRef CFCreateString(); |
| 131 | CFTypeRef CFGetSomething(); |
| 132 | CFStringRef CFGetString(); |
| 133 | |
| 134 | id CreateSomething(); |
| 135 | NSString *CreateNSString(); |
| 136 | |
| 137 | void from_cf() { |
| 138 | id obj1 = (__bridge_transfer id)CFCreateSomething(); // expected-warning{{never read}} |
| 139 | id obj2 = (__bridge_transfer NSString*)CFCreateString(); |
| 140 | [obj2 self]; // Add a use, to show we can use the object after it has been transfered. |
| 141 | id obj3 = (__bridge id)CFGetSomething(); |
| 142 | [obj3 self]; // Add a use, to show we can use the object after it has been bridged. |
| 143 | id obj4 = (__bridge NSString*)CFGetString(); // expected-warning{{never read}} |
| 144 | id obj5 = (__bridge id)CFCreateSomething(); // expected-warning{{never read}} expected-warning{{leak}} |
| 145 | id obj6 = (__bridge NSString*)CFCreateString(); // expected-warning{{never read}} expected-warning{{leak}} |
| 146 | } |
| 147 | |
| 148 | void to_cf(id obj) { |
| 149 | CFTypeRef cf1 = (__bridge_retained CFTypeRef)CreateSomething(); // expected-warning{{never read}} |
| 150 | CFStringRef cf2 = (__bridge_retained CFStringRef)CreateNSString(); // expected-warning{{never read}} |
| 151 | CFTypeRef cf3 = (__bridge CFTypeRef)CreateSomething(); // expected-warning{{never read}} |
| 152 | CFStringRef cf4 = (__bridge CFStringRef)CreateNSString(); // expected-warning{{never read}} |
| 153 | } |
| 154 | |
| 155 | void test_objc_retainedObject() { |
| 156 | CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); |
| 157 | CFDateRef date = CFDateCreate(0, t); |
| 158 | id x = objc_retainedObject(date); |
| 159 | (void) x; |
| 160 | } |
| 161 | |
| 162 | void test_objc_unretainedObject() { |
| 163 | CFAbsoluteTime t = CFAbsoluteTimeGetCurrent(); |
| 164 | CFDateRef date = CFDateCreate(0, t); // expected-warning {{Potential leak}} |
| 165 | id x = objc_unretainedObject(date); |
| 166 | (void) x; |
| 167 | } |
| 168 | |
Ted Kremenek | 05a4652 | 2011-08-27 21:15:48 +0000 | [diff] [blame] | 169 | // Previously this resulted in a "return of stack address" warning. |
| 170 | id test_return() { |
| 171 | id x = (__bridge_transfer id) CFCreateString(); |
| 172 | return x; // no-warning |
| 173 | } |
| 174 | |
Ted Kremenek | 1a45a5f | 2012-03-06 20:06:12 +0000 | [diff] [blame] | 175 | void test_objc_arrays() { |
| 176 | { // CASE ONE -- OBJECT IN ARRAY CREATED DIRECTLY |
| 177 | NSObject *o = [[NSObject alloc] init]; |
| 178 | NSArray *a = [[NSArray alloc] initWithObjects:o, (void*)0]; |
| 179 | [a description]; |
| 180 | [o description]; |
| 181 | } |
| 182 | |
| 183 | { // CASE TWO -- OBJECT IN ARRAY CREATED BY DUPING AUTORELEASED ARRAY |
| 184 | NSObject *o = [[NSObject alloc] init]; |
| 185 | NSArray *a1 = [NSArray arrayWithObjects:o, (void*)0]; |
| 186 | NSArray *a2 = [[NSArray alloc] initWithArray:a1]; |
| 187 | [a2 description]; |
| 188 | [o description]; |
| 189 | } |
| 190 | |
| 191 | { // CASE THREE -- OBJECT IN RETAINED @[] |
| 192 | NSObject *o = [[NSObject alloc] init]; |
| 193 | NSArray *a3 = @[o]; |
| 194 | [a3 description]; |
| 195 | [o description]; |
| 196 | } |
| 197 | { |
| 198 | // CASE 4, verify analyzer still working. |
| 199 | CFCreateString(); // expected-warning {{leak}} |
| 200 | } |
| 201 | } |
| 202 | |
Ted Kremenek | 06911d4 | 2012-03-22 06:29:41 +0000 | [diff] [blame] | 203 | // <rdar://problem/11059275> - dispatch_set_context and ARC. |
| 204 | __attribute__((cf_returns_retained)) CFTypeRef CFBridgingRetain(id X); |
| 205 | typedef void* dispatch_object_t; |
| 206 | void dispatch_set_context(dispatch_object_t object, const void *context); |
| 207 | |
| 208 | void rdar11059275(dispatch_object_t object) { |
| 209 | NSObject *o = [[NSObject alloc] init]; |
| 210 | dispatch_set_context(object, CFBridgingRetain(o)); // no-warning |
| 211 | } |
| 212 | void rdar11059275_positive() { |
| 213 | NSObject *o = [[NSObject alloc] init]; // expected-warning {{leak}} |
| 214 | CFBridgingRetain(o); |
| 215 | } |
| 216 | void rdar11059275_negative() { |
| 217 | NSObject *o = [[NSObject alloc] init]; // no-warning |
| 218 | (void) o; |
| 219 | } |
Ted Kremenek | 1a45a5f | 2012-03-06 20:06:12 +0000 | [diff] [blame] | 220 | |