Dominic Chen | 184c624 | 2017-03-03 18:02:02 +0000 | [diff] [blame] | 1 | // RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount -analyzer-output=text -analyzer-config suppress-null-return-paths=false -fblocks -verify %s |
George Karpenkov | 3916509 | 2018-06-12 19:07:41 +0000 | [diff] [blame] | 2 | // RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount -analyzer-output=plist-multi-file -analyzer-config suppress-null-return-paths=false -fblocks %s -o %t.plist |
Mikhail Maltsev | c704f4d | 2018-09-17 10:19:46 +0000 | [diff] [blame] | 3 | // RUN: cat %t.plist | %diff_plist %S/Inputs/expected-plists/path-notes.m.plist |
Jordan Rose | 6f3d2f0 | 2012-09-22 01:24:49 +0000 | [diff] [blame] | 4 | |
Jordan Rose | 2d98b97 | 2012-11-15 02:07:23 +0000 | [diff] [blame] | 5 | typedef struct dispatch_queue_s *dispatch_queue_t; |
| 6 | typedef void (^dispatch_block_t)(void); |
| 7 | void dispatch_sync(dispatch_queue_t, dispatch_block_t); |
| 8 | |
Jordan Rose | 5fbe7f9 | 2013-08-01 22:16:30 +0000 | [diff] [blame] | 9 | typedef long dispatch_once_t; |
| 10 | // Note: The real dispatch_once has all parameters marked nonnull. |
| 11 | // We don't do that here so that we can trigger a null dereference inside |
| 12 | // the synthesized body. |
| 13 | void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block); |
| 14 | |
Jordan Rose | 2d98b97 | 2012-11-15 02:07:23 +0000 | [diff] [blame] | 15 | |
Jordan Rose | 6f3d2f0 | 2012-09-22 01:24:49 +0000 | [diff] [blame] | 16 | @interface Test |
| 17 | @property int *p; |
| 18 | @end |
| 19 | |
Anna Zaks | 6afa8f1 | 2013-05-13 23:49:51 +0000 | [diff] [blame] | 20 | typedef unsigned long NSUInteger; |
| 21 | typedef signed char BOOL; |
| 22 | typedef struct _NSZone NSZone; |
| 23 | @class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; |
| 24 | @protocol NSObject |
| 25 | @end |
| 26 | @protocol NSCopying |
| 27 | - (id)copyWithZone:(NSZone *)zone; |
| 28 | @end |
| 29 | @protocol NSMutableCopying |
| 30 | - (id)mutableCopyWithZone:(NSZone *)zone; |
| 31 | @end |
| 32 | @protocol NSCoding |
| 33 | - (void)encodeWithCoder:(NSCoder *)aCoder; |
| 34 | @end |
| 35 | @protocol NSFastEnumeration |
| 36 | @end |
| 37 | @protocol NSSecureCoding <NSCoding> |
| 38 | @required |
| 39 | + (BOOL)supportsSecureCoding; |
| 40 | @end |
| 41 | @interface NSObject <NSObject> {} |
| 42 | - (id)init; |
| 43 | + (id)alloc; |
Jordan Rose | 5fbe7f9 | 2013-08-01 22:16:30 +0000 | [diff] [blame] | 44 | - (id)autorelease; |
Anna Zaks | 6afa8f1 | 2013-05-13 23:49:51 +0000 | [diff] [blame] | 45 | @end |
| 46 | @interface NSArray : NSObject <NSCopying, NSMutableCopying, NSSecureCoding, NSFastEnumeration> |
| 47 | |
| 48 | - (NSUInteger)count; |
| 49 | - (id)objectAtIndex:(NSUInteger)index; |
| 50 | |
| 51 | @end |
| 52 | |
| 53 | @interface NSArray (NSExtendedArray) |
| 54 | - (NSArray *)arrayByAddingObject:(id)anObject; |
| 55 | - (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx __attribute__((availability(macosx,introduced=10.8))); |
| 56 | @end |
| 57 | |
| 58 | @interface NSArray (NSArrayCreation) |
| 59 | + (instancetype)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt; |
| 60 | @end |
| 61 | |
| 62 | @interface NSMutableArray : NSArray |
| 63 | |
| 64 | - (void)addObject:(id)anObject; |
| 65 | - (void)insertObject:(id)anObject atIndex:(NSUInteger)index; |
| 66 | - (void)removeLastObject; |
| 67 | - (void)removeObjectAtIndex:(NSUInteger)index; |
| 68 | - (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject; |
| 69 | |
| 70 | @end |
| 71 | |
Jordan Rose | 6f3d2f0 | 2012-09-22 01:24:49 +0000 | [diff] [blame] | 72 | int *getZeroIfNil(Test *x) { |
| 73 | return x.p; |
Ted Kremenek | d51ad8c | 2013-04-18 17:44:15 +0000 | [diff] [blame] | 74 | // expected-note@-1 {{'p' not called because the receiver is nil}} |
Jordan Rose | 6f3d2f0 | 2012-09-22 01:24:49 +0000 | [diff] [blame] | 75 | // expected-note@-2 {{Returning null pointer}} |
| 76 | } |
| 77 | |
| 78 | void testReturnZeroIfNil() { |
| 79 | *getZeroIfNil(0) = 1; // expected-warning{{Dereference of null pointer}} |
| 80 | // expected-note@-1 {{Calling 'getZeroIfNil'}} |
| 81 | // expected-note@-2 {{Passing nil object reference via 1st parameter 'x'}} |
| 82 | // expected-note@-3 {{Returning from 'getZeroIfNil'}} |
| 83 | // expected-note@-4 {{Dereference of null pointer}} |
| 84 | } |
| 85 | |
| 86 | |
Jordan Rose | 2d98b97 | 2012-11-15 02:07:23 +0000 | [diff] [blame] | 87 | int testDispatchSyncInlining() { |
| 88 | extern dispatch_queue_t globalQueue; |
| 89 | |
| 90 | __block int x; |
| 91 | |
| 92 | // expected-note@+2 {{Calling 'dispatch_sync'}} |
| 93 | // expected-note@+1 {{Returning from 'dispatch_sync'}} |
| 94 | dispatch_sync(globalQueue, ^{ |
Jordan Rose | 5613826 | 2013-05-24 21:43:11 +0000 | [diff] [blame] | 95 | // expected-note@-1 {{Calling anonymous block}} |
| 96 | // expected-note@-2 {{Returning to caller}} |
Jordan Rose | 2d98b97 | 2012-11-15 02:07:23 +0000 | [diff] [blame] | 97 | x = 0; |
| 98 | // expected-note@-1 {{The value 0 is assigned to 'x'}} |
Jordan Rose | 2d98b97 | 2012-11-15 02:07:23 +0000 | [diff] [blame] | 99 | }); |
| 100 | |
| 101 | return 1 / x; // expected-warning{{Division by zero}} |
| 102 | // expected-note@-1 {{Division by zero}} |
| 103 | } |
| 104 | |
Jordan Rose | 9a33913 | 2012-12-07 19:56:29 +0000 | [diff] [blame] | 105 | int testDispatchSyncInliningNoPruning(int coin) { |
| 106 | // This tests exactly the same case as above, except on a bug report where |
| 107 | // path pruning is disabled (an uninitialized variable capture). |
| 108 | // In this case |
| 109 | extern dispatch_queue_t globalQueue; |
| 110 | |
| 111 | __block int y; |
| 112 | |
| 113 | // expected-note@+1 {{Calling 'dispatch_sync'}} |
| 114 | dispatch_sync(globalQueue, ^{ |
Jordan Rose | 5613826 | 2013-05-24 21:43:11 +0000 | [diff] [blame] | 115 | // expected-note@-1 {{Calling anonymous block}} |
Jordan Rose | 9a33913 | 2012-12-07 19:56:29 +0000 | [diff] [blame] | 116 | int x; |
Ted Kremenek | 37c777e | 2013-02-26 19:44:38 +0000 | [diff] [blame] | 117 | // expected-note@-1 {{'x' declared without an initial value}} |
Jordan Rose | 9a33913 | 2012-12-07 19:56:29 +0000 | [diff] [blame] | 118 | ^{ y = x; }(); // expected-warning{{Variable 'x' is uninitialized when captured by block}} |
Ted Kremenek | 37c777e | 2013-02-26 19:44:38 +0000 | [diff] [blame] | 119 | // expected-note@-1 {{'x' is uninitialized when captured by block}} |
Jordan Rose | 9a33913 | 2012-12-07 19:56:29 +0000 | [diff] [blame] | 120 | }); |
| 121 | |
| 122 | return y; |
| 123 | } |
| 124 | |
Jordan Rose | 2d98b97 | 2012-11-15 02:07:23 +0000 | [diff] [blame] | 125 | |
Jordan Rose | cea47b7 | 2013-05-03 05:47:24 +0000 | [diff] [blame] | 126 | @interface PointerWrapper |
| 127 | - (int *)getPtr; |
| 128 | @end |
| 129 | |
| 130 | id getNil() { |
| 131 | return 0; |
| 132 | } |
| 133 | |
| 134 | void testNilReceiverHelper(int *x) { |
| 135 | *x = 1; // expected-warning {{Dereference of null pointer}} |
| 136 | // expected-note@-1 {{Dereference of null pointer (loaded from variable 'x')}} |
| 137 | } |
| 138 | |
Artem Dergachev | fee1010 | 2017-12-20 01:03:22 +0000 | [diff] [blame] | 139 | void testNilReceiver(id *x, id *y, id *z) { |
| 140 | // FIXME: Should say "Assuming pointer value is null" instead. |
| 141 | // For some reason we're displaying different notes for |
| 142 | // tracked and untracked pointers. |
| 143 | if (*y) {} // expected-note {{Assuming the condition is false}} |
| 144 | // expected-note@-1 {{Taking false branch}} |
| 145 | if (*x) { // expected-note {{Assuming pointer value is null}} |
Jordan Rose | cea47b7 | 2013-05-03 05:47:24 +0000 | [diff] [blame] | 146 | // expected-note@-1 {{Taking false branch}} |
| 147 | return; |
| 148 | } |
Artem Dergachev | fee1010 | 2017-12-20 01:03:22 +0000 | [diff] [blame] | 149 | // FIXME: Should say "Assuming pointer value is null" instead. |
| 150 | if (*z) {} // expected-note {{Assuming the condition is false}} |
| 151 | // expected-note@-1 {{Taking false branch}} |
Jordan Rose | cea47b7 | 2013-05-03 05:47:24 +0000 | [diff] [blame] | 152 | testNilReceiverHelper([*x getPtr]); |
| 153 | // expected-note@-1 {{'getPtr' not called because the receiver is nil}} |
| 154 | // expected-note@-2 {{Passing null pointer value via 1st parameter 'x'}} |
| 155 | // expected-note@-3 {{Calling 'testNilReceiverHelper'}} |
| 156 | } |
| 157 | |
Anna Zaks | 6afa8f1 | 2013-05-13 23:49:51 +0000 | [diff] [blame] | 158 | id testCreateArrayLiteral(id myNil) { |
| 159 | if (myNil) // expected-note {{Assuming 'myNil' is nil}} |
| 160 | ; // expected-note@-1 {{Taking false branch}} |
| 161 | return @[ @"a", myNil, @"c" ]; // expected-warning {{Array element cannot be nil}} |
| 162 | //expected-note@-1 {{Array element cannot be nil}} |
| 163 | } |
Jordan Rose | cea47b7 | 2013-05-03 05:47:24 +0000 | [diff] [blame] | 164 | |
Jordan Rose | 5fbe7f9 | 2013-08-01 22:16:30 +0000 | [diff] [blame] | 165 | // <rdar://problem/14611722> |
| 166 | id testAutoreleaseTakesEffectInDispatch() { |
| 167 | static dispatch_once_t token = 0; |
| 168 | dispatch_once(&token, ^{}); |
| 169 | |
| 170 | id x = [[[[NSObject alloc] init] autorelease] autorelease]; |
Anna Zaks | 232ecfd | 2016-12-15 22:55:03 +0000 | [diff] [blame] | 171 | // expected-note@-1 {{Method returns an instance of NSObject with a +1 retain count}} |
Jordan Rose | 7699e4a | 2013-08-01 22:16:36 +0000 | [diff] [blame] | 172 | // expected-note@-2 {{Object autoreleased}} |
| 173 | // expected-note@-3 {{Object autoreleased}} |
Jordan Rose | 5fbe7f9 | 2013-08-01 22:16:30 +0000 | [diff] [blame] | 174 | |
Jordan Rose | 7699e4a | 2013-08-01 22:16:36 +0000 | [diff] [blame] | 175 | dispatch_once(&token, ^{}); // don't crash, don't warn here |
Jordan Rose | 5fbe7f9 | 2013-08-01 22:16:30 +0000 | [diff] [blame] | 176 | |
Jordan Rose | 7699e4a | 2013-08-01 22:16:36 +0000 | [diff] [blame] | 177 | return x; // expected-warning{{Object autoreleased too many times}} |
| 178 | // expected-note@-1 {{Object was autoreleased 2 times but the object has a +0 retain count}} |
Jordan Rose | 5fbe7f9 | 2013-08-01 22:16:30 +0000 | [diff] [blame] | 179 | } |
| 180 | |
| 181 | void testNullDereferenceInDispatch() { |
| 182 | dispatch_once(0, ^{}); // no-warning, don't crash |
| 183 | } |
| 184 | |