blob: 220a38118aa2f1fa5f90c185f378d134d5c40ded [file] [log] [blame]
Anna Zaksad9e7ea2016-01-29 18:43:15 +00001// RUN: %clang_cc1 -fblocks -analyze -analyzer-checker=core,nullability -verify %s
Gabor Horvath28690922015-08-26 23:17:43 +00002
3#define nil 0
4#define BOOL int
5
Devin Coughlinde217672016-01-28 22:23:34 +00006#define NS_ASSUME_NONNULL_BEGIN _Pragma("clang assume_nonnull begin")
7#define NS_ASSUME_NONNULL_END _Pragma("clang assume_nonnull end")
8
9typedef struct _NSZone NSZone;
10
Gabor Horvath28690922015-08-26 23:17:43 +000011@protocol NSObject
12+ (id)alloc;
13- (id)init;
14@end
15
Devin Coughlinde217672016-01-28 22:23:34 +000016NS_ASSUME_NONNULL_BEGIN
Gabor Horvath28690922015-08-26 23:17:43 +000017@protocol NSCopying
Devin Coughlinde217672016-01-28 22:23:34 +000018- (id)copyWithZone:(nullable NSZone *)zone;
19
Gabor Horvath28690922015-08-26 23:17:43 +000020@end
21
Devin Coughlinde217672016-01-28 22:23:34 +000022@protocol NSMutableCopying
23- (id)mutableCopyWithZone:(nullable NSZone *)zone;
24@end
25NS_ASSUME_NONNULL_END
26
Gabor Horvath28690922015-08-26 23:17:43 +000027__attribute__((objc_root_class))
28@interface
29NSObject<NSObject>
30@end
31
32@interface NSString : NSObject<NSCopying>
33- (BOOL)isEqualToString : (NSString *_Nonnull)aString;
34- (NSString *)stringByAppendingString:(NSString *_Nonnull)aString;
35@end
36
37@interface TestObject : NSObject
38- (int *_Nonnull)returnsNonnull;
39- (int *_Nullable)returnsNullable;
40- (int *)returnsUnspecified;
41- (void)takesNonnull:(int *_Nonnull)p;
42- (void)takesNullable:(int *_Nullable)p;
43- (void)takesUnspecified:(int *)p;
44@property(readonly, strong) NSString *stuff;
45@end
46
47TestObject * getUnspecifiedTestObject();
48TestObject *_Nonnull getNonnullTestObject();
49TestObject *_Nullable getNullableTestObject();
50
51int getRandom();
52
53typedef struct Dummy { int val; } Dummy;
54
55void takesNullable(Dummy *_Nullable);
56void takesNonnull(Dummy *_Nonnull);
57void takesUnspecified(Dummy *);
58
59Dummy *_Nullable returnsNullable();
60Dummy *_Nonnull returnsNonnull();
61Dummy *returnsUnspecified();
62int *_Nullable returnsNullableInt();
63
64template <typename T> T *eraseNullab(T *p) { return p; }
65
Gabor Horvath8d3ad6b2015-08-27 18:49:07 +000066void takesAttrNonnull(Dummy *p) __attribute((nonnull(1)));
67
Gabor Horvath28690922015-08-26 23:17:43 +000068void testBasicRules() {
69 Dummy *p = returnsNullable();
70 int *ptr = returnsNullableInt();
71 // Make every dereference a different path to avoid sinks after errors.
72 switch (getRandom()) {
73 case 0: {
Anna Zaksad9e7ea2016-01-29 18:43:15 +000074 Dummy &r = *p; // expected-warning {{Nullable pointer is dereferenced}}
Gabor Horvath28690922015-08-26 23:17:43 +000075 } break;
76 case 1: {
Anna Zaksad9e7ea2016-01-29 18:43:15 +000077 int b = p->val; // expected-warning {{Nullable pointer is dereferenced}}
Gabor Horvath28690922015-08-26 23:17:43 +000078 } break;
79 case 2: {
Anna Zaksad9e7ea2016-01-29 18:43:15 +000080 int stuff = *ptr; // expected-warning {{Nullable pointer is dereferenced}}
Gabor Horvath28690922015-08-26 23:17:43 +000081 } break;
82 case 3:
Anna Zaksad9e7ea2016-01-29 18:43:15 +000083 takesNonnull(p); // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
Gabor Horvath28690922015-08-26 23:17:43 +000084 break;
85 case 4: {
86 Dummy d;
87 takesNullable(&d);
88 Dummy dd(d);
89 break;
90 }
Gabor Horvath8d3ad6b2015-08-27 18:49:07 +000091 case 5: takesAttrNonnull(p); break; // expected-warning {{Nullable pointer is passed to}}
92 default: { Dummy d = *p; } break; // expected-warning {{Nullable pointer is dereferenced}}
Gabor Horvath28690922015-08-26 23:17:43 +000093 }
94 if (p) {
95 takesNonnull(p);
96 if (getRandom()) {
97 Dummy &r = *p;
98 } else {
99 int b = p->val;
100 }
101 }
102 Dummy *q = 0;
103 if (getRandom()) {
104 takesNullable(q);
Anna Zaksad9e7ea2016-01-29 18:43:15 +0000105 takesNonnull(q); // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}
Gabor Horvath28690922015-08-26 23:17:43 +0000106 }
107 Dummy a;
108 Dummy *_Nonnull nonnull = &a;
Anna Zaksad9e7ea2016-01-29 18:43:15 +0000109 nonnull = q; // expected-warning {{Null is assigned to a pointer which is expected to have non-null value}}
Gabor Horvath28690922015-08-26 23:17:43 +0000110 q = &a;
111 takesNullable(q);
112 takesNonnull(q);
113}
114
115void testMultiParamChecking(Dummy *_Nonnull a, Dummy *_Nullable b,
116 Dummy *_Nonnull c);
117
118void testArgumentTracking(Dummy *_Nonnull nonnull, Dummy *_Nullable nullable) {
119 Dummy *p = nullable;
120 Dummy *q = nonnull;
121 switch(getRandom()) {
Anna Zaksad9e7ea2016-01-29 18:43:15 +0000122 case 1: nonnull = p; break; // expected-warning {{Nullable pointer is assigned to a pointer which is expected to have non-null value}}
Gabor Horvath28690922015-08-26 23:17:43 +0000123 case 2: p = 0; break;
124 case 3: q = p; break;
125 case 4: testMultiParamChecking(nonnull, nullable, nonnull); break;
126 case 5: testMultiParamChecking(nonnull, nonnull, nonnull); break;
Anna Zaksad9e7ea2016-01-29 18:43:15 +0000127 case 6: testMultiParamChecking(nonnull, nullable, nullable); break; // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 3rd parameter}}
128 case 7: testMultiParamChecking(nullable, nullable, nonnull); // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
129 case 8: testMultiParamChecking(nullable, nullable, nullable); // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
Gabor Horvath28690922015-08-26 23:17:43 +0000130 case 9: testMultiParamChecking((Dummy *_Nonnull)0, nullable, nonnull); break;
131 }
132}
133
134Dummy *_Nonnull testNullableReturn(Dummy *_Nullable a) {
135 Dummy *p = a;
Devin Coughlin5a3843e2016-01-18 18:53:33 +0000136 return p; // expected-warning {{Nullable pointer is returned from a function that is expected to return a non-null value}}
Gabor Horvath28690922015-08-26 23:17:43 +0000137}
138
139Dummy *_Nonnull testNullReturn() {
140 Dummy *p = 0;
Devin Coughlin5a3843e2016-01-18 18:53:33 +0000141 return p; // expected-warning {{Null is returned from a function that is expected to return a non-null value}}
Gabor Horvath28690922015-08-26 23:17:43 +0000142}
143
144void testObjCMessageResultNullability() {
145 // The expected result: the most nullable of self and method return type.
146 TestObject *o = getUnspecifiedTestObject();
147 int *shouldBeNullable = [eraseNullab(getNullableTestObject()) returnsNonnull];
148 switch (getRandom()) {
149 case 0:
150 // The core analyzer assumes that the receiver is non-null after a message
151 // send. This is to avoid some false positives, and increase performance
152 // but it also reduces the coverage and makes this checker unable to reason
153 // about the nullness of the receiver.
154 [o takesNonnull:shouldBeNullable]; // No warning expected.
155 break;
156 case 1:
157 shouldBeNullable =
158 [eraseNullab(getNullableTestObject()) returnsUnspecified];
159 [o takesNonnull:shouldBeNullable]; // No warning expected.
160 break;
161 case 3:
162 shouldBeNullable = [eraseNullab(getNullableTestObject()) returnsNullable];
Anna Zaksad9e7ea2016-01-29 18:43:15 +0000163 [o takesNonnull:shouldBeNullable]; // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
Gabor Horvath28690922015-08-26 23:17:43 +0000164 break;
165 case 4:
166 shouldBeNullable = [eraseNullab(getNonnullTestObject()) returnsNullable];
Anna Zaksad9e7ea2016-01-29 18:43:15 +0000167 [o takesNonnull:shouldBeNullable]; // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
Gabor Horvath28690922015-08-26 23:17:43 +0000168 break;
169 case 5:
170 shouldBeNullable =
171 [eraseNullab(getUnspecifiedTestObject()) returnsNullable];
Anna Zaksad9e7ea2016-01-29 18:43:15 +0000172 [o takesNonnull:shouldBeNullable]; // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
Gabor Horvath28690922015-08-26 23:17:43 +0000173 break;
174 case 6:
175 shouldBeNullable = [eraseNullab(getNullableTestObject()) returnsNullable];
Anna Zaksad9e7ea2016-01-29 18:43:15 +0000176 [o takesNonnull:shouldBeNullable]; // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
Gabor Horvath28690922015-08-26 23:17:43 +0000177 break;
178 case 7: {
179 int *shouldBeNonnull = [eraseNullab(getNonnullTestObject()) returnsNonnull];
180 [o takesNonnull:shouldBeNonnull];
181 } break;
182 }
183}
184
Devin Coughlin755baa42015-12-29 17:40:49 +0000185Dummy * _Nonnull testDirectCastNullableToNonnull() {
186 Dummy *p = returnsNullable();
187 takesNonnull((Dummy * _Nonnull)p); // no-warning
188 return (Dummy * _Nonnull)p; // no-warning
189}
190
191Dummy * _Nonnull testIndirectCastNullableToNonnull() {
Gabor Horvath28690922015-08-26 23:17:43 +0000192 Dummy *p = (Dummy * _Nonnull)returnsNullable();
Devin Coughlin755baa42015-12-29 17:40:49 +0000193 takesNonnull(p); // no-warning
194 return p; // no-warning
195}
196
197Dummy * _Nonnull testDirectCastNilToNonnull() {
198 takesNonnull((Dummy * _Nonnull)0); // no-warning
199 return (Dummy * _Nonnull)0; // no-warning
200}
201
202void testIndirectCastNilToNonnullAndPass() {
203 Dummy *p = (Dummy * _Nonnull)0;
204 // FIXME: Ideally the cast above would suppress this warning.
Anna Zaksad9e7ea2016-01-29 18:43:15 +0000205 takesNonnull(p); // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}
206}
207
208void testIndirectNilPassToNonnull() {
209 Dummy *p = 0;
210 takesNonnull(p); // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}
211}
212
213void testConditionalNilPassToNonnull(Dummy *p) {
214 if (!p) {
215 takesNonnull(p); // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}
216 }
Devin Coughlin755baa42015-12-29 17:40:49 +0000217}
218
219Dummy * _Nonnull testIndirectCastNilToNonnullAndReturn() {
220 Dummy *p = (Dummy * _Nonnull)0;
221 // FIXME: Ideally the cast above would suppress this warning.
222 return p; // expected-warning {{Null is returned from a function that is expected to return a non-null value}}
Gabor Horvath28690922015-08-26 23:17:43 +0000223}
224
225void testInvalidPropagation() {
226 Dummy *p = returnsUnspecified();
227 takesNullable(p);
228 takesNonnull(p);
229}
Gabor Horvathb47128a2015-09-03 23:16:21 +0000230
231void onlyReportFirstPreconditionViolationOnPath() {
232 Dummy *p = returnsNullable();
Anna Zaksad9e7ea2016-01-29 18:43:15 +0000233 takesNonnull(p); // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
Gabor Horvathb47128a2015-09-03 23:16:21 +0000234 takesNonnull(p); // No warning.
235 // The first warning was not a sink. The analysis expected to continue.
236 int i = 0;
237 i = 5 / i; // expected-warning {{Division by zero}}
238 (void)i;
239}
240
241Dummy *_Nonnull doNotWarnWhenPreconditionIsViolatedInTopFunc(
242 Dummy *_Nonnull p) {
243 if (!p) {
244 Dummy *ret =
245 0; // avoid compiler warning (which is not generated by the analyzer)
246 if (getRandom())
247 return ret; // no warning
248 else
249 return p; // no warning
250 } else {
251 return p;
252 }
253}
254
255Dummy *_Nonnull doNotWarnWhenPreconditionIsViolated(Dummy *_Nonnull p) {
256 if (!p) {
257 Dummy *ret =
258 0; // avoid compiler warning (which is not generated by the analyzer)
259 if (getRandom())
260 return ret; // no warning
261 else
262 return p; // no warning
263 } else {
264 return p;
265 }
266}
267
268void testPreconditionViolationInInlinedFunction(Dummy *p) {
269 doNotWarnWhenPreconditionIsViolated(p);
270}
271
272void inlinedNullable(Dummy *_Nullable p) {
273 if (p) return;
274}
275void inlinedNonnull(Dummy *_Nonnull p) {
276 if (p) return;
277}
278void inlinedUnspecified(Dummy *p) {
279 if (p) return;
280}
281
Anna Zaksad9e7ea2016-01-29 18:43:15 +0000282void testNilReturnWithBlock(Dummy *p) {
283 p = 0;
284 Dummy *_Nonnull (^myblock)(void) = ^Dummy *_Nonnull(void) {
285 return p; // TODO: We should warn in blocks.
286 };
287 myblock();
288}
289
Gabor Horvathb47128a2015-09-03 23:16:21 +0000290Dummy *_Nonnull testDefensiveInlineChecks(Dummy * p) {
291 switch (getRandom()) {
292 case 1: inlinedNullable(p); break;
293 case 2: inlinedNonnull(p); break;
294 case 3: inlinedUnspecified(p); break;
295 }
296 if (getRandom())
Devin Coughlinc1986632015-11-24 19:15:11 +0000297 takesNonnull(p); // no-warning
298
299 if (getRandom()) {
300 Dummy *_Nonnull varWithInitializer = p; // no-warning
301
302 Dummy *_Nonnull var1WithInitializer = p, // no-warning
303 *_Nonnull var2WithInitializer = p; // no-warning
304 }
305
306 if (getRandom()) {
307 Dummy *_Nonnull varWithoutInitializer;
308 varWithoutInitializer = p; // no-warning
309 }
310
Gabor Horvathb47128a2015-09-03 23:16:21 +0000311 return p;
312}
Devin Coughlin3ab8b2e72015-12-29 23:44:19 +0000313
Devin Coughlin4a330202016-01-22 01:01:11 +0000314
315@interface SomeClass : NSObject {
316 int instanceVar;
317}
Devin Coughlin5a3843e2016-01-18 18:53:33 +0000318@end
319
320@implementation SomeClass (MethodReturn)
Devin Coughlin4a330202016-01-22 01:01:11 +0000321- (id)initWithSomething:(int)i {
322 if (self = [super init]) {
323 instanceVar = i;
324 }
325
326 return self;
327}
328
Devin Coughlin5a3843e2016-01-18 18:53:33 +0000329- (TestObject * _Nonnull)testReturnsNullableInNonnullIndirectly {
330 TestObject *local = getNullableTestObject();
Anna Zaksad9e7ea2016-01-29 18:43:15 +0000331 return local; // expected-warning {{Nullable pointer is returned from a method that is expected to return a non-null value}}
Devin Coughlin3ab8b2e72015-12-29 23:44:19 +0000332}
333
Devin Coughlin5a3843e2016-01-18 18:53:33 +0000334- (TestObject * _Nonnull)testReturnsCastSuppressedNullableInNonnullIndirectly {
335 TestObject *local = getNullableTestObject();
336 return (TestObject * _Nonnull)local; // no-warning
Devin Coughlin3ab8b2e72015-12-29 23:44:19 +0000337}
Devin Coughlin5a3843e2016-01-18 18:53:33 +0000338
339- (TestObject * _Nonnull)testReturnsNullableInNonnullWhenPreconditionViolated:(TestObject * _Nonnull) p {
340 TestObject *local = getNullableTestObject();
341 if (!p) // Pre-condition violated here.
342 return local; // no-warning
343 else
344 return p; // no-warning
345}
346@end
Devin Coughlin4a330202016-01-22 01:01:11 +0000347
348@interface ClassWithInitializers : NSObject
349@end
350
351@implementation ClassWithInitializers
352- (instancetype _Nonnull)initWithNonnullReturnAndSelfCheckingIdiom {
353 // This defensive check is a common-enough idiom that we filter don't want
354 // to issue a diagnostic for it,
355 if (self = [super init]) {
356 }
357
358 return self; // no-warning
359}
360
361- (instancetype _Nonnull)initWithNonnullReturnAndNilReturnViaLocal {
362 self = [super init];
363 // This leaks, but we're not checking for that here.
364
365 ClassWithInitializers *other = nil;
Devin Coughlinde217672016-01-28 22:23:34 +0000366 // False negative. Once we have more subtle suppression of defensive checks in
367 // initializers we should warn here.
368 return other;
Devin Coughlin4a330202016-01-22 01:01:11 +0000369}
370@end
371
372@interface SubClassWithInitializers : ClassWithInitializers
373@end
374
375@implementation SubClassWithInitializers
376// Note: Because this is overridding
377// -[ClassWithInitializers initWithNonnullReturnAndSelfCheckingIdiom],
378// the return type of this method becomes implicitly id _Nonnull.
379- (id)initWithNonnullReturnAndSelfCheckingIdiom {
380 if (self = [super initWithNonnullReturnAndSelfCheckingIdiom]) {
381 }
382
383 return self; // no-warning
384}
Devin Coughlinde217672016-01-28 22:23:34 +0000385
386- (id _Nonnull)initWithNonnullReturnAndSelfCheckingIdiomV2; {
387 // Another common return-checking idiom
388 self = [super initWithNonnullReturnAndSelfCheckingIdiom];
389 if (!self) {
390 return nil; // no-warning
391 }
392
393 return self;
394}
395@end
396
397@interface ClassWithCopyWithZone : NSObject<NSCopying,NSMutableCopying> {
398 id i;
399}
400
401@end
402
403@implementation ClassWithCopyWithZone
404-(id)copyWithZone:(NSZone *)zone {
405 ClassWithCopyWithZone *newInstance = [[ClassWithCopyWithZone alloc] init];
406 if (!newInstance)
407 return nil;
408
409 newInstance->i = i;
410 return newInstance;
411}
412
413-(id)mutableCopyWithZone:(NSZone *)zone {
414 ClassWithCopyWithZone *newInstance = [[ClassWithCopyWithZone alloc] init];
415 if (newInstance) {
416 newInstance->i = i;
417 }
418
419 return newInstance;
420}
Devin Coughlin4a330202016-01-22 01:01:11 +0000421@end