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: %normalize_plist <%t.plist | diff -ub %S/Inputs/expected-plists/path-notes.m.plist -
4
5typedef struct dispatch_queue_s *dispatch_queue_t;
6typedef void (^dispatch_block_t)(void);
7void dispatch_sync(dispatch_queue_t, dispatch_block_t);
8
9typedef 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.
13void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block);
14
15
16@interface Test
17@property int *p;
18@end
19
20typedef unsigned long NSUInteger;
21typedef signed char BOOL;
22typedef 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
72int *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
78void 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
87int 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
105int 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
130id getNil() {
131  return 0;
132}
133
134void 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
139void 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
158id 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>
166id 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
181void testNullDereferenceInDispatch() {
182  dispatch_once(0, ^{}); // no-warning, don't crash
183}
184
185