blob: d4deecd9b5bf2f74c795c045b177d8d1c2517e54 [file] [log] [blame]
Devin Coughlina1d9d752016-03-05 01:32:43 +00001// RUN: %clang_cc1 -fblocks -analyze -analyzer-checker=core,nullability -DNOSYSTEMHEADERS=0 -verify %s
2// RUN: %clang_cc1 -fblocks -analyze -analyzer-checker=core,nullability -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 Zaksad9e7ea2016-01-29 18:43:15 +000078 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 +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;
Devin Coughlin5a3843e2016-01-18 18:53:33 +0000110 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 +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
177void testIndirectNilPassToNonnull() {
178 Dummy *p = 0;
179 takesNonnull(p); // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}
180}
181
182void testConditionalNilPassToNonnull(Dummy *p) {
183 if (!p) {
184 takesNonnull(p); // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}
185 }
Devin Coughlin755baa42015-12-29 17:40:49 +0000186}
187
188Dummy * _Nonnull testIndirectCastNilToNonnullAndReturn() {
189 Dummy *p = (Dummy * _Nonnull)0;
190 // FIXME: Ideally the cast above would suppress this warning.
191 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 +0000192}
193
194void testInvalidPropagation() {
195 Dummy *p = returnsUnspecified();
196 takesNullable(p);
197 takesNonnull(p);
198}
Gabor Horvathb47128a2015-09-03 23:16:21 +0000199
200void onlyReportFirstPreconditionViolationOnPath() {
201 Dummy *p = returnsNullable();
Anna Zaksad9e7ea2016-01-29 18:43:15 +0000202 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 +0000203 takesNonnull(p); // No warning.
204 // The first warning was not a sink. The analysis expected to continue.
205 int i = 0;
206 i = 5 / i; // expected-warning {{Division by zero}}
207 (void)i;
208}
209
210Dummy *_Nonnull doNotWarnWhenPreconditionIsViolatedInTopFunc(
211 Dummy *_Nonnull p) {
212 if (!p) {
213 Dummy *ret =
214 0; // avoid compiler warning (which is not generated by the analyzer)
215 if (getRandom())
216 return ret; // no warning
217 else
218 return p; // no warning
219 } else {
220 return p;
221 }
222}
223
224Dummy *_Nonnull doNotWarnWhenPreconditionIsViolated(Dummy *_Nonnull p) {
225 if (!p) {
226 Dummy *ret =
227 0; // avoid compiler warning (which is not generated by the analyzer)
228 if (getRandom())
229 return ret; // no warning
230 else
231 return p; // no warning
232 } else {
233 return p;
234 }
235}
236
237void testPreconditionViolationInInlinedFunction(Dummy *p) {
238 doNotWarnWhenPreconditionIsViolated(p);
239}
240
Devin Coughlin49bd58f2016-04-12 19:29:52 +0000241@interface TestInlinedPreconditionViolationClass : NSObject
242@end
243
244@implementation TestInlinedPreconditionViolationClass
245-(Dummy * _Nonnull) calleeWithParam:(Dummy * _Nonnull) p2 {
246 Dummy *x = 0;
247 if (!p2) // p2 binding becomes dead at this point.
248 return x; // no-warning
249 else
250 return p2;
251}
252
253-(Dummy *)callerWithParam:(Dummy * _Nonnull) p1 {
254 return [self calleeWithParam:p1];
255}
256
257@end
258
259int * _Nonnull InlinedPreconditionViolationInFunctionCallee(int * _Nonnull p2) {
260 int *x = 0;
261 if (!p2) // p2 binding becomes dead at this point.
262 return x; // no-warning
263 else
264 return p2;
265}
266
267int * _Nonnull InlinedReturnNullOverSuppressionCallee(int * _Nonnull p2) {
268 int *result = 0;
269 return result; // no-warning; but this is an over suppression
270}
271
272int *InlinedReturnNullOverSuppressionCaller(int * _Nonnull p1) {
273 return InlinedReturnNullOverSuppressionCallee(p1);
274}
275
Gabor Horvathb47128a2015-09-03 23:16:21 +0000276void inlinedNullable(Dummy *_Nullable p) {
277 if (p) return;
278}
279void inlinedNonnull(Dummy *_Nonnull p) {
280 if (p) return;
281}
282void inlinedUnspecified(Dummy *p) {
283 if (p) return;
284}
285
Anna Zaksad9e7ea2016-01-29 18:43:15 +0000286void testNilReturnWithBlock(Dummy *p) {
287 p = 0;
288 Dummy *_Nonnull (^myblock)(void) = ^Dummy *_Nonnull(void) {
289 return p; // TODO: We should warn in blocks.
290 };
291 myblock();
292}
293
Gabor Horvathb47128a2015-09-03 23:16:21 +0000294Dummy *_Nonnull testDefensiveInlineChecks(Dummy * p) {
295 switch (getRandom()) {
296 case 1: inlinedNullable(p); break;
297 case 2: inlinedNonnull(p); break;
298 case 3: inlinedUnspecified(p); break;
299 }
300 if (getRandom())
Devin Coughlinc1986632015-11-24 19:15:11 +0000301 takesNonnull(p); // no-warning
302
303 if (getRandom()) {
304 Dummy *_Nonnull varWithInitializer = p; // no-warning
305
306 Dummy *_Nonnull var1WithInitializer = p, // no-warning
307 *_Nonnull var2WithInitializer = p; // no-warning
308 }
309
310 if (getRandom()) {
311 Dummy *_Nonnull varWithoutInitializer;
312 varWithoutInitializer = p; // no-warning
313 }
314
Gabor Horvathb47128a2015-09-03 23:16:21 +0000315 return p;
316}
Devin Coughlin3ab8b2e72015-12-29 23:44:19 +0000317
Devin Coughlin4a330202016-01-22 01:01:11 +0000318
319@interface SomeClass : NSObject {
320 int instanceVar;
321}
Devin Coughlin5a3843e2016-01-18 18:53:33 +0000322@end
323
324@implementation SomeClass (MethodReturn)
Devin Coughlin4a330202016-01-22 01:01:11 +0000325- (id)initWithSomething:(int)i {
326 if (self = [super init]) {
327 instanceVar = i;
328 }
329
330 return self;
331}
332
Devin Coughlin5a3843e2016-01-18 18:53:33 +0000333- (TestObject * _Nonnull)testReturnsNullableInNonnullIndirectly {
334 TestObject *local = getNullableTestObject();
Anna Zaksad9e7ea2016-01-29 18:43:15 +0000335 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 +0000336}
337
Devin Coughlin5a3843e2016-01-18 18:53:33 +0000338- (TestObject * _Nonnull)testReturnsCastSuppressedNullableInNonnullIndirectly {
339 TestObject *local = getNullableTestObject();
340 return (TestObject * _Nonnull)local; // no-warning
Devin Coughlin3ab8b2e72015-12-29 23:44:19 +0000341}
Devin Coughlin5a3843e2016-01-18 18:53:33 +0000342
343- (TestObject * _Nonnull)testReturnsNullableInNonnullWhenPreconditionViolated:(TestObject * _Nonnull) p {
344 TestObject *local = getNullableTestObject();
345 if (!p) // Pre-condition violated here.
346 return local; // no-warning
347 else
348 return p; // no-warning
349}
350@end
Devin Coughlin4a330202016-01-22 01:01:11 +0000351
352@interface ClassWithInitializers : NSObject
353@end
354
355@implementation ClassWithInitializers
356- (instancetype _Nonnull)initWithNonnullReturnAndSelfCheckingIdiom {
357 // This defensive check is a common-enough idiom that we filter don't want
358 // to issue a diagnostic for it,
359 if (self = [super init]) {
360 }
361
362 return self; // no-warning
363}
364
365- (instancetype _Nonnull)initWithNonnullReturnAndNilReturnViaLocal {
366 self = [super init];
367 // This leaks, but we're not checking for that here.
368
369 ClassWithInitializers *other = nil;
Devin Coughlinde217672016-01-28 22:23:34 +0000370 // False negative. Once we have more subtle suppression of defensive checks in
371 // initializers we should warn here.
372 return other;
Devin Coughlin4a330202016-01-22 01:01:11 +0000373}
374@end
375
376@interface SubClassWithInitializers : ClassWithInitializers
377@end
378
379@implementation SubClassWithInitializers
380// Note: Because this is overridding
381// -[ClassWithInitializers initWithNonnullReturnAndSelfCheckingIdiom],
382// the return type of this method becomes implicitly id _Nonnull.
383- (id)initWithNonnullReturnAndSelfCheckingIdiom {
384 if (self = [super initWithNonnullReturnAndSelfCheckingIdiom]) {
385 }
386
387 return self; // no-warning
388}
Devin Coughlinde217672016-01-28 22:23:34 +0000389
390- (id _Nonnull)initWithNonnullReturnAndSelfCheckingIdiomV2; {
391 // Another common return-checking idiom
392 self = [super initWithNonnullReturnAndSelfCheckingIdiom];
393 if (!self) {
394 return nil; // no-warning
395 }
396
397 return self;
398}
399@end
400
401@interface ClassWithCopyWithZone : NSObject<NSCopying,NSMutableCopying> {
402 id i;
403}
404
405@end
406
407@implementation ClassWithCopyWithZone
408-(id)copyWithZone:(NSZone *)zone {
409 ClassWithCopyWithZone *newInstance = [[ClassWithCopyWithZone alloc] init];
410 if (!newInstance)
411 return nil;
412
413 newInstance->i = i;
414 return newInstance;
415}
416
417-(id)mutableCopyWithZone:(NSZone *)zone {
418 ClassWithCopyWithZone *newInstance = [[ClassWithCopyWithZone alloc] init];
419 if (newInstance) {
420 newInstance->i = i;
421 }
422
423 return newInstance;
424}
Devin Coughlin4a330202016-01-22 01:01:11 +0000425@end
Devin Coughlina1d9d752016-03-05 01:32:43 +0000426
427NSString * _Nullable returnsNullableString();
428
429void callFunctionInSystemHeader() {
430 NSString *s = returnsNullableString();
431
432 NSSystemFunctionTakingNonnull(s);
433 #if !NOSYSTEMHEADERS
434 // expected-warning@-2{{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
435 #endif
436}
437
438void callMethodInSystemHeader() {
439 NSString *s = returnsNullableString();
440
441 NSSystemClass *sc = [[NSSystemClass alloc] init];
442 [sc takesNonnull:s];
443 #if !NOSYSTEMHEADERS
444 // expected-warning@-2{{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
445 #endif
446}
Devin Coughlinb2d2a012016-04-13 00:41:54 +0000447
448// Test to make sure the analyzer doesn't warn when an a nullability invariant
449// has already been found to be violated on an instance variable.
450
451@class MyInternalClass;
452@interface MyClass : NSObject {
453 MyInternalClass * _Nonnull _internal;
454}
455@end
456
457@interface MyInternalClass : NSObject {
458 @public
459 id _someIvar;
460}
461-(id _Nonnull)methodWithInternalImplementation;
462@end
463
464@interface MyClass () {
465 MyInternalClass * _Nonnull _nilledOutInternal;
466}
467@end
468
469@implementation MyClass
470-(id _Nonnull)methodWithInternalImplementation {
471 if (!_internal)
472 return nil; // no-warning
473
474 return [_internal methodWithInternalImplementation];
475}
476
477- (id _Nonnull)methodReturningIvarInImplementation; {
478 return _internal == 0 ? nil : _internal->_someIvar; // no-warning
479}
480
481-(id _Nonnull)methodWithNilledOutInternal {
482 // The cast below should (but does not yet) suppress the warning on the
483 // assignment.
484 _nilledOutInternal = (id _Nonnull)nil; // expected-warning {{Null is assigned to a pointer which is expected to have non-null value}}
485
486 return nil; // no-warning
487}
488@end