blob: ddfede53b59dc21c5521a0041a6583b7f8d1f190 [file] [log] [blame]
Dominic Chen184c6242017-03-03 18:02:02 +00001// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,nullability.NullableDereferenced -DNOSYSTEMHEADERS=0 -verify %s
2// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,nullability.NullableDereferenced -analyzer-config nullability:NoDiagnoseCallsToSystemHeaders=true -DNOSYSTEMHEADERS=1 -verify %s
Gabor Horvath28690922015-08-26 23:17:43 +00003
Devin Coughlina1d9d752016-03-05 01:32:43 +00004#include "Inputs/system-header-simulator-for-nullability.h"
Gabor Horvath28690922015-08-26 23:17:43 +00005
6@interface TestObject : NSObject
7- (int *_Nonnull)returnsNonnull;
8- (int *_Nullable)returnsNullable;
9- (int *)returnsUnspecified;
10- (void)takesNonnull:(int *_Nonnull)p;
11- (void)takesNullable:(int *_Nullable)p;
12- (void)takesUnspecified:(int *)p;
13@property(readonly, strong) NSString *stuff;
14@end
15
16TestObject * getUnspecifiedTestObject();
17TestObject *_Nonnull getNonnullTestObject();
18TestObject *_Nullable getNullableTestObject();
19
20int getRandom();
21
22typedef struct Dummy { int val; } Dummy;
23
24void takesNullable(Dummy *_Nullable);
25void takesNonnull(Dummy *_Nonnull);
26void takesUnspecified(Dummy *);
27
28Dummy *_Nullable returnsNullable();
29Dummy *_Nonnull returnsNonnull();
30Dummy *returnsUnspecified();
31int *_Nullable returnsNullableInt();
32
33template <typename T> T *eraseNullab(T *p) { return p; }
34
Gabor Horvath8d3ad6b2015-08-27 18:49:07 +000035void takesAttrNonnull(Dummy *p) __attribute((nonnull(1)));
36
Gabor Horvath28690922015-08-26 23:17:43 +000037void testBasicRules() {
38 Dummy *p = returnsNullable();
39 int *ptr = returnsNullableInt();
40 // Make every dereference a different path to avoid sinks after errors.
41 switch (getRandom()) {
42 case 0: {
Anna Zaksad9e7ea2016-01-29 18:43:15 +000043 Dummy &r = *p; // expected-warning {{Nullable pointer is dereferenced}}
Gabor Horvath28690922015-08-26 23:17:43 +000044 } break;
45 case 1: {
Anna Zaksad9e7ea2016-01-29 18:43:15 +000046 int b = p->val; // expected-warning {{Nullable pointer is dereferenced}}
Gabor Horvath28690922015-08-26 23:17:43 +000047 } break;
48 case 2: {
Anna Zaksad9e7ea2016-01-29 18:43:15 +000049 int stuff = *ptr; // expected-warning {{Nullable pointer is dereferenced}}
Gabor Horvath28690922015-08-26 23:17:43 +000050 } break;
51 case 3:
Anna Zaksad9e7ea2016-01-29 18:43:15 +000052 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 +000053 break;
54 case 4: {
55 Dummy d;
56 takesNullable(&d);
57 Dummy dd(d);
58 break;
59 }
Gabor Horvath8d3ad6b2015-08-27 18:49:07 +000060 case 5: takesAttrNonnull(p); break; // expected-warning {{Nullable pointer is passed to}}
61 default: { Dummy d = *p; } break; // expected-warning {{Nullable pointer is dereferenced}}
Gabor Horvath28690922015-08-26 23:17:43 +000062 }
63 if (p) {
64 takesNonnull(p);
65 if (getRandom()) {
66 Dummy &r = *p;
67 } else {
68 int b = p->val;
69 }
70 }
71 Dummy *q = 0;
72 if (getRandom()) {
73 takesNullable(q);
Anna Zaksad9e7ea2016-01-29 18:43:15 +000074 takesNonnull(q); // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}
Gabor Horvath28690922015-08-26 23:17:43 +000075 }
76 Dummy a;
77 Dummy *_Nonnull nonnull = &a;
Anna Zaks6d4e76b2016-12-15 22:55:15 +000078 nonnull = q; // expected-warning {{Null assigned to a pointer which is expected to have non-null value}}
Gabor Horvath28690922015-08-26 23:17:43 +000079 q = &a;
80 takesNullable(q);
81 takesNonnull(q);
82}
83
84void testMultiParamChecking(Dummy *_Nonnull a, Dummy *_Nullable b,
85 Dummy *_Nonnull c);
86
87void testArgumentTracking(Dummy *_Nonnull nonnull, Dummy *_Nullable nullable) {
88 Dummy *p = nullable;
89 Dummy *q = nonnull;
90 switch(getRandom()) {
Anna Zaksad9e7ea2016-01-29 18:43:15 +000091 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 +000092 case 2: p = 0; break;
93 case 3: q = p; break;
94 case 4: testMultiParamChecking(nonnull, nullable, nonnull); break;
95 case 5: testMultiParamChecking(nonnull, nonnull, nonnull); break;
Anna Zaksad9e7ea2016-01-29 18:43:15 +000096 case 6: testMultiParamChecking(nonnull, nullable, nullable); break; // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 3rd parameter}}
97 case 7: testMultiParamChecking(nullable, nullable, nonnull); // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
98 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 +000099 case 9: testMultiParamChecking((Dummy *_Nonnull)0, nullable, nonnull); break;
100 }
101}
102
103Dummy *_Nonnull testNullableReturn(Dummy *_Nullable a) {
104 Dummy *p = a;
Devin Coughlin5a3843e2016-01-18 18:53:33 +0000105 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 +0000106}
107
108Dummy *_Nonnull testNullReturn() {
109 Dummy *p = 0;
Anna Zaks6d4e76b2016-12-15 22:55:15 +0000110 return p; // expected-warning {{Null returned from a function that is expected to return a non-null value}}
Gabor Horvath28690922015-08-26 23:17:43 +0000111}
112
113void testObjCMessageResultNullability() {
114 // The expected result: the most nullable of self and method return type.
115 TestObject *o = getUnspecifiedTestObject();
116 int *shouldBeNullable = [eraseNullab(getNullableTestObject()) returnsNonnull];
117 switch (getRandom()) {
118 case 0:
119 // The core analyzer assumes that the receiver is non-null after a message
120 // send. This is to avoid some false positives, and increase performance
121 // but it also reduces the coverage and makes this checker unable to reason
122 // about the nullness of the receiver.
123 [o takesNonnull:shouldBeNullable]; // No warning expected.
124 break;
125 case 1:
126 shouldBeNullable =
127 [eraseNullab(getNullableTestObject()) returnsUnspecified];
128 [o takesNonnull:shouldBeNullable]; // No warning expected.
129 break;
130 case 3:
131 shouldBeNullable = [eraseNullab(getNullableTestObject()) returnsNullable];
Anna Zaksad9e7ea2016-01-29 18:43:15 +0000132 [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 +0000133 break;
134 case 4:
135 shouldBeNullable = [eraseNullab(getNonnullTestObject()) returnsNullable];
Anna Zaksad9e7ea2016-01-29 18:43:15 +0000136 [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 +0000137 break;
138 case 5:
139 shouldBeNullable =
140 [eraseNullab(getUnspecifiedTestObject()) returnsNullable];
Anna Zaksad9e7ea2016-01-29 18:43:15 +0000141 [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 +0000142 break;
143 case 6:
144 shouldBeNullable = [eraseNullab(getNullableTestObject()) returnsNullable];
Anna Zaksad9e7ea2016-01-29 18:43:15 +0000145 [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 +0000146 break;
147 case 7: {
148 int *shouldBeNonnull = [eraseNullab(getNonnullTestObject()) returnsNonnull];
149 [o takesNonnull:shouldBeNonnull];
150 } break;
151 }
152}
153
Devin Coughlin755baa42015-12-29 17:40:49 +0000154Dummy * _Nonnull testDirectCastNullableToNonnull() {
155 Dummy *p = returnsNullable();
156 takesNonnull((Dummy * _Nonnull)p); // no-warning
157 return (Dummy * _Nonnull)p; // no-warning
158}
159
160Dummy * _Nonnull testIndirectCastNullableToNonnull() {
Gabor Horvath28690922015-08-26 23:17:43 +0000161 Dummy *p = (Dummy * _Nonnull)returnsNullable();
Devin Coughlin755baa42015-12-29 17:40:49 +0000162 takesNonnull(p); // no-warning
163 return p; // no-warning
164}
165
166Dummy * _Nonnull testDirectCastNilToNonnull() {
167 takesNonnull((Dummy * _Nonnull)0); // no-warning
168 return (Dummy * _Nonnull)0; // no-warning
169}
170
171void testIndirectCastNilToNonnullAndPass() {
172 Dummy *p = (Dummy * _Nonnull)0;
173 // FIXME: Ideally the cast above would suppress this warning.
Anna Zaksad9e7ea2016-01-29 18:43:15 +0000174 takesNonnull(p); // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}
175}
176
Devin Coughlin4ac12422016-04-13 17:59:24 +0000177void testDirectCastNilToNonnullAndAssignToLocalInInitializer() {
178 Dummy * _Nonnull nonnullLocalWithAssignmentInInitializer = (Dummy * _Nonnull)0; // no-warning
179 (void)nonnullLocalWithAssignmentInInitializer;
180
181 // Since we've already had an invariant violation along this path,
182 // we shouldn't warn here.
183 nonnullLocalWithAssignmentInInitializer = 0;
184 (void)nonnullLocalWithAssignmentInInitializer;
185
186}
187
188void testDirectCastNilToNonnullAndAssignToLocal(Dummy * _Nonnull p) {
189 Dummy * _Nonnull nonnullLocalWithAssignment = p;
190 nonnullLocalWithAssignment = (Dummy * _Nonnull)0; // no-warning
191 (void)nonnullLocalWithAssignment;
192
193 // Since we've already had an invariant violation along this path,
194 // we shouldn't warn here.
195 nonnullLocalWithAssignment = 0;
196 (void)nonnullLocalWithAssignment;
197}
198
199void testDirectCastNilToNonnullAndAssignToParam(Dummy * _Nonnull p) {
200 p = (Dummy * _Nonnull)0; // no-warning
201}
202
203@interface ClassWithNonnullIvar : NSObject {
204 Dummy *_nonnullIvar;
205}
206@end
207
208@implementation ClassWithNonnullIvar
209-(void)testDirectCastNilToNonnullAndAssignToIvar {
210 _nonnullIvar = (Dummy * _Nonnull)0; // no-warning;
211
212 // Since we've already had an invariant violation along this path,
213 // we shouldn't warn here.
214 _nonnullIvar = 0;
215}
216@end
217
Anna Zaksad9e7ea2016-01-29 18:43:15 +0000218void testIndirectNilPassToNonnull() {
219 Dummy *p = 0;
220 takesNonnull(p); // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}
221}
222
223void testConditionalNilPassToNonnull(Dummy *p) {
224 if (!p) {
225 takesNonnull(p); // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}
226 }
Devin Coughlin755baa42015-12-29 17:40:49 +0000227}
228
229Dummy * _Nonnull testIndirectCastNilToNonnullAndReturn() {
230 Dummy *p = (Dummy * _Nonnull)0;
231 // FIXME: Ideally the cast above would suppress this warning.
Anna Zaks6d4e76b2016-12-15 22:55:15 +0000232 return p; // expected-warning {{Null returned from a function that is expected to return a non-null value}}
Gabor Horvath28690922015-08-26 23:17:43 +0000233}
234
235void testInvalidPropagation() {
236 Dummy *p = returnsUnspecified();
237 takesNullable(p);
238 takesNonnull(p);
239}
Gabor Horvathb47128a2015-09-03 23:16:21 +0000240
241void onlyReportFirstPreconditionViolationOnPath() {
242 Dummy *p = returnsNullable();
Anna Zaksad9e7ea2016-01-29 18:43:15 +0000243 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 +0000244 takesNonnull(p); // No warning.
245 // The first warning was not a sink. The analysis expected to continue.
246 int i = 0;
247 i = 5 / i; // expected-warning {{Division by zero}}
248 (void)i;
249}
250
251Dummy *_Nonnull doNotWarnWhenPreconditionIsViolatedInTopFunc(
252 Dummy *_Nonnull p) {
253 if (!p) {
254 Dummy *ret =
255 0; // avoid compiler warning (which is not generated by the analyzer)
256 if (getRandom())
257 return ret; // no warning
258 else
259 return p; // no warning
260 } else {
261 return p;
262 }
263}
264
265Dummy *_Nonnull doNotWarnWhenPreconditionIsViolated(Dummy *_Nonnull p) {
266 if (!p) {
267 Dummy *ret =
268 0; // avoid compiler warning (which is not generated by the analyzer)
269 if (getRandom())
270 return ret; // no warning
271 else
272 return p; // no warning
273 } else {
274 return p;
275 }
276}
277
278void testPreconditionViolationInInlinedFunction(Dummy *p) {
279 doNotWarnWhenPreconditionIsViolated(p);
280}
281
Devin Coughlin49bd58f2016-04-12 19:29:52 +0000282@interface TestInlinedPreconditionViolationClass : NSObject
283@end
284
285@implementation TestInlinedPreconditionViolationClass
286-(Dummy * _Nonnull) calleeWithParam:(Dummy * _Nonnull) p2 {
287 Dummy *x = 0;
288 if (!p2) // p2 binding becomes dead at this point.
289 return x; // no-warning
290 else
291 return p2;
292}
293
294-(Dummy *)callerWithParam:(Dummy * _Nonnull) p1 {
295 return [self calleeWithParam:p1];
296}
297
298@end
299
300int * _Nonnull InlinedPreconditionViolationInFunctionCallee(int * _Nonnull p2) {
301 int *x = 0;
302 if (!p2) // p2 binding becomes dead at this point.
303 return x; // no-warning
304 else
305 return p2;
306}
307
308int * _Nonnull InlinedReturnNullOverSuppressionCallee(int * _Nonnull p2) {
309 int *result = 0;
310 return result; // no-warning; but this is an over suppression
311}
312
313int *InlinedReturnNullOverSuppressionCaller(int * _Nonnull p1) {
314 return InlinedReturnNullOverSuppressionCallee(p1);
315}
316
Gabor Horvathb47128a2015-09-03 23:16:21 +0000317void inlinedNullable(Dummy *_Nullable p) {
318 if (p) return;
319}
320void inlinedNonnull(Dummy *_Nonnull p) {
321 if (p) return;
322}
323void inlinedUnspecified(Dummy *p) {
324 if (p) return;
325}
326
Anna Zaksad9e7ea2016-01-29 18:43:15 +0000327void testNilReturnWithBlock(Dummy *p) {
328 p = 0;
329 Dummy *_Nonnull (^myblock)(void) = ^Dummy *_Nonnull(void) {
330 return p; // TODO: We should warn in blocks.
331 };
332 myblock();
333}
334
Gabor Horvathb47128a2015-09-03 23:16:21 +0000335Dummy *_Nonnull testDefensiveInlineChecks(Dummy * p) {
336 switch (getRandom()) {
337 case 1: inlinedNullable(p); break;
338 case 2: inlinedNonnull(p); break;
339 case 3: inlinedUnspecified(p); break;
340 }
341 if (getRandom())
Devin Coughlinc1986632015-11-24 19:15:11 +0000342 takesNonnull(p); // no-warning
343
344 if (getRandom()) {
345 Dummy *_Nonnull varWithInitializer = p; // no-warning
346
347 Dummy *_Nonnull var1WithInitializer = p, // no-warning
348 *_Nonnull var2WithInitializer = p; // no-warning
349 }
350
351 if (getRandom()) {
352 Dummy *_Nonnull varWithoutInitializer;
353 varWithoutInitializer = p; // no-warning
354 }
355
Gabor Horvathb47128a2015-09-03 23:16:21 +0000356 return p;
357}
Devin Coughlin3ab8b2e72015-12-29 23:44:19 +0000358
Devin Coughlin4a330202016-01-22 01:01:11 +0000359
360@interface SomeClass : NSObject {
361 int instanceVar;
362}
Devin Coughlin5a3843e2016-01-18 18:53:33 +0000363@end
364
365@implementation SomeClass (MethodReturn)
Devin Coughlin4a330202016-01-22 01:01:11 +0000366- (id)initWithSomething:(int)i {
367 if (self = [super init]) {
368 instanceVar = i;
369 }
370
371 return self;
372}
373
Devin Coughlin5a3843e2016-01-18 18:53:33 +0000374- (TestObject * _Nonnull)testReturnsNullableInNonnullIndirectly {
375 TestObject *local = getNullableTestObject();
Anna Zaksad9e7ea2016-01-29 18:43:15 +0000376 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 +0000377}
378
Devin Coughlin5a3843e2016-01-18 18:53:33 +0000379- (TestObject * _Nonnull)testReturnsCastSuppressedNullableInNonnullIndirectly {
380 TestObject *local = getNullableTestObject();
381 return (TestObject * _Nonnull)local; // no-warning
Devin Coughlin3ab8b2e72015-12-29 23:44:19 +0000382}
Devin Coughlin5a3843e2016-01-18 18:53:33 +0000383
384- (TestObject * _Nonnull)testReturnsNullableInNonnullWhenPreconditionViolated:(TestObject * _Nonnull) p {
385 TestObject *local = getNullableTestObject();
386 if (!p) // Pre-condition violated here.
387 return local; // no-warning
388 else
389 return p; // no-warning
390}
391@end
Devin Coughlin4a330202016-01-22 01:01:11 +0000392
393@interface ClassWithInitializers : NSObject
394@end
395
396@implementation ClassWithInitializers
397- (instancetype _Nonnull)initWithNonnullReturnAndSelfCheckingIdiom {
398 // This defensive check is a common-enough idiom that we filter don't want
399 // to issue a diagnostic for it,
400 if (self = [super init]) {
401 }
402
403 return self; // no-warning
404}
405
406- (instancetype _Nonnull)initWithNonnullReturnAndNilReturnViaLocal {
407 self = [super init];
408 // This leaks, but we're not checking for that here.
409
410 ClassWithInitializers *other = nil;
Devin Coughlinde217672016-01-28 22:23:34 +0000411 // False negative. Once we have more subtle suppression of defensive checks in
412 // initializers we should warn here.
413 return other;
Devin Coughlin4a330202016-01-22 01:01:11 +0000414}
415@end
416
417@interface SubClassWithInitializers : ClassWithInitializers
418@end
419
420@implementation SubClassWithInitializers
421// Note: Because this is overridding
422// -[ClassWithInitializers initWithNonnullReturnAndSelfCheckingIdiom],
423// the return type of this method becomes implicitly id _Nonnull.
424- (id)initWithNonnullReturnAndSelfCheckingIdiom {
425 if (self = [super initWithNonnullReturnAndSelfCheckingIdiom]) {
426 }
427
428 return self; // no-warning
429}
Devin Coughlinde217672016-01-28 22:23:34 +0000430
431- (id _Nonnull)initWithNonnullReturnAndSelfCheckingIdiomV2; {
432 // Another common return-checking idiom
433 self = [super initWithNonnullReturnAndSelfCheckingIdiom];
434 if (!self) {
435 return nil; // no-warning
436 }
437
438 return self;
439}
440@end
441
442@interface ClassWithCopyWithZone : NSObject<NSCopying,NSMutableCopying> {
443 id i;
444}
445
446@end
447
448@implementation ClassWithCopyWithZone
449-(id)copyWithZone:(NSZone *)zone {
450 ClassWithCopyWithZone *newInstance = [[ClassWithCopyWithZone alloc] init];
451 if (!newInstance)
452 return nil;
453
454 newInstance->i = i;
455 return newInstance;
456}
457
458-(id)mutableCopyWithZone:(NSZone *)zone {
459 ClassWithCopyWithZone *newInstance = [[ClassWithCopyWithZone alloc] init];
460 if (newInstance) {
461 newInstance->i = i;
462 }
463
464 return newInstance;
465}
Devin Coughlin4a330202016-01-22 01:01:11 +0000466@end
Devin Coughlina1d9d752016-03-05 01:32:43 +0000467
468NSString * _Nullable returnsNullableString();
469
470void callFunctionInSystemHeader() {
471 NSString *s = returnsNullableString();
472
473 NSSystemFunctionTakingNonnull(s);
474 #if !NOSYSTEMHEADERS
475 // expected-warning@-2{{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
476 #endif
477}
478
479void callMethodInSystemHeader() {
480 NSString *s = returnsNullableString();
481
482 NSSystemClass *sc = [[NSSystemClass alloc] init];
483 [sc takesNonnull:s];
484 #if !NOSYSTEMHEADERS
485 // expected-warning@-2{{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
486 #endif
487}
Devin Coughlinb2d2a012016-04-13 00:41:54 +0000488
489// Test to make sure the analyzer doesn't warn when an a nullability invariant
490// has already been found to be violated on an instance variable.
491
492@class MyInternalClass;
493@interface MyClass : NSObject {
494 MyInternalClass * _Nonnull _internal;
495}
496@end
497
498@interface MyInternalClass : NSObject {
499 @public
500 id _someIvar;
501}
502-(id _Nonnull)methodWithInternalImplementation;
503@end
504
505@interface MyClass () {
506 MyInternalClass * _Nonnull _nilledOutInternal;
507}
508@end
509
510@implementation MyClass
511-(id _Nonnull)methodWithInternalImplementation {
512 if (!_internal)
513 return nil; // no-warning
514
515 return [_internal methodWithInternalImplementation];
516}
517
518- (id _Nonnull)methodReturningIvarInImplementation; {
519 return _internal == 0 ? nil : _internal->_someIvar; // no-warning
520}
521
522-(id _Nonnull)methodWithNilledOutInternal {
Devin Coughlin4ac12422016-04-13 17:59:24 +0000523 _nilledOutInternal = (id _Nonnull)nil;
Devin Coughlinb2d2a012016-04-13 00:41:54 +0000524
525 return nil; // no-warning
526}
527@end