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 |
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 |
3 | // RUN: cat %t.plist | %diff_plist %S/Inputs/expected-plists/path-notes.m.plist - |
4 | |
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 | |
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 | |
15 | |
16 | @interface Test |
17 | @property int *p; |
18 | @end |
19 | |
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; |
44 | - (id)autorelease; |
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 | |
72 | int *getZeroIfNil(Test *x) { |
73 | return x.p; |
74 | // expected-note@-1 {{'p' not called because the receiver is nil}} |
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 | |
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, ^{ |
95 | // expected-note@-1 {{Calling anonymous block}} |
96 | // expected-note@-2 {{Returning to caller}} |
97 | x = 0; |
98 | // expected-note@-1 {{The value 0 is assigned to 'x'}} |
99 | }); |
100 | |
101 | return 1 / x; // expected-warning{{Division by zero}} |
102 | // expected-note@-1 {{Division by zero}} |
103 | } |
104 | |
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, ^{ |
115 | // expected-note@-1 {{Calling anonymous block}} |
116 | int x; |
117 | // expected-note@-1 {{'x' declared without an initial value}} |
118 | ^{ y = x; }(); // expected-warning{{Variable 'x' is uninitialized when captured by block}} |
119 | // expected-note@-1 {{'x' is uninitialized when captured by block}} |
120 | }); |
121 | |
122 | return y; |
123 | } |
124 | |
125 | |
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 | |
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}} |
146 | // expected-note@-1 {{Taking false branch}} |
147 | return; |
148 | } |
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}} |
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 | |
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 | } |
164 | |
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]; |
171 | // expected-note@-1 {{Method returns an instance of NSObject with a +1 retain count}} |
172 | // expected-note@-2 {{Object autoreleased}} |
173 | // expected-note@-3 {{Object autoreleased}} |
174 | |
175 | dispatch_once(&token, ^{}); // don't crash, don't warn here |
176 | |
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}} |
179 | } |
180 | |
181 | void testNullDereferenceInDispatch() { |
182 | dispatch_once(0, ^{}); // no-warning, don't crash |
183 | } |
184 | |
185 | |