blob: 0a3ae7a1968c6fedc83aea25f32b1a042d35fd07 [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
241void inlinedNullable(Dummy *_Nullable p) {
242 if (p) return;
243}
244void inlinedNonnull(Dummy *_Nonnull p) {
245 if (p) return;
246}
247void inlinedUnspecified(Dummy *p) {
248 if (p) return;
249}
250
Anna Zaksad9e7ea2016-01-29 18:43:15 +0000251void testNilReturnWithBlock(Dummy *p) {
252 p = 0;
253 Dummy *_Nonnull (^myblock)(void) = ^Dummy *_Nonnull(void) {
254 return p; // TODO: We should warn in blocks.
255 };
256 myblock();
257}
258
Gabor Horvathb47128a2015-09-03 23:16:21 +0000259Dummy *_Nonnull testDefensiveInlineChecks(Dummy * p) {
260 switch (getRandom()) {
261 case 1: inlinedNullable(p); break;
262 case 2: inlinedNonnull(p); break;
263 case 3: inlinedUnspecified(p); break;
264 }
265 if (getRandom())
Devin Coughlinc1986632015-11-24 19:15:11 +0000266 takesNonnull(p); // no-warning
267
268 if (getRandom()) {
269 Dummy *_Nonnull varWithInitializer = p; // no-warning
270
271 Dummy *_Nonnull var1WithInitializer = p, // no-warning
272 *_Nonnull var2WithInitializer = p; // no-warning
273 }
274
275 if (getRandom()) {
276 Dummy *_Nonnull varWithoutInitializer;
277 varWithoutInitializer = p; // no-warning
278 }
279
Gabor Horvathb47128a2015-09-03 23:16:21 +0000280 return p;
281}
Devin Coughlin3ab8b2e72015-12-29 23:44:19 +0000282
Devin Coughlin4a330202016-01-22 01:01:11 +0000283
284@interface SomeClass : NSObject {
285 int instanceVar;
286}
Devin Coughlin5a3843e2016-01-18 18:53:33 +0000287@end
288
289@implementation SomeClass (MethodReturn)
Devin Coughlin4a330202016-01-22 01:01:11 +0000290- (id)initWithSomething:(int)i {
291 if (self = [super init]) {
292 instanceVar = i;
293 }
294
295 return self;
296}
297
Devin Coughlin5a3843e2016-01-18 18:53:33 +0000298- (TestObject * _Nonnull)testReturnsNullableInNonnullIndirectly {
299 TestObject *local = getNullableTestObject();
Anna Zaksad9e7ea2016-01-29 18:43:15 +0000300 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 +0000301}
302
Devin Coughlin5a3843e2016-01-18 18:53:33 +0000303- (TestObject * _Nonnull)testReturnsCastSuppressedNullableInNonnullIndirectly {
304 TestObject *local = getNullableTestObject();
305 return (TestObject * _Nonnull)local; // no-warning
Devin Coughlin3ab8b2e72015-12-29 23:44:19 +0000306}
Devin Coughlin5a3843e2016-01-18 18:53:33 +0000307
308- (TestObject * _Nonnull)testReturnsNullableInNonnullWhenPreconditionViolated:(TestObject * _Nonnull) p {
309 TestObject *local = getNullableTestObject();
310 if (!p) // Pre-condition violated here.
311 return local; // no-warning
312 else
313 return p; // no-warning
314}
315@end
Devin Coughlin4a330202016-01-22 01:01:11 +0000316
317@interface ClassWithInitializers : NSObject
318@end
319
320@implementation ClassWithInitializers
321- (instancetype _Nonnull)initWithNonnullReturnAndSelfCheckingIdiom {
322 // This defensive check is a common-enough idiom that we filter don't want
323 // to issue a diagnostic for it,
324 if (self = [super init]) {
325 }
326
327 return self; // no-warning
328}
329
330- (instancetype _Nonnull)initWithNonnullReturnAndNilReturnViaLocal {
331 self = [super init];
332 // This leaks, but we're not checking for that here.
333
334 ClassWithInitializers *other = nil;
Devin Coughlinde217672016-01-28 22:23:34 +0000335 // False negative. Once we have more subtle suppression of defensive checks in
336 // initializers we should warn here.
337 return other;
Devin Coughlin4a330202016-01-22 01:01:11 +0000338}
339@end
340
341@interface SubClassWithInitializers : ClassWithInitializers
342@end
343
344@implementation SubClassWithInitializers
345// Note: Because this is overridding
346// -[ClassWithInitializers initWithNonnullReturnAndSelfCheckingIdiom],
347// the return type of this method becomes implicitly id _Nonnull.
348- (id)initWithNonnullReturnAndSelfCheckingIdiom {
349 if (self = [super initWithNonnullReturnAndSelfCheckingIdiom]) {
350 }
351
352 return self; // no-warning
353}
Devin Coughlinde217672016-01-28 22:23:34 +0000354
355- (id _Nonnull)initWithNonnullReturnAndSelfCheckingIdiomV2; {
356 // Another common return-checking idiom
357 self = [super initWithNonnullReturnAndSelfCheckingIdiom];
358 if (!self) {
359 return nil; // no-warning
360 }
361
362 return self;
363}
364@end
365
366@interface ClassWithCopyWithZone : NSObject<NSCopying,NSMutableCopying> {
367 id i;
368}
369
370@end
371
372@implementation ClassWithCopyWithZone
373-(id)copyWithZone:(NSZone *)zone {
374 ClassWithCopyWithZone *newInstance = [[ClassWithCopyWithZone alloc] init];
375 if (!newInstance)
376 return nil;
377
378 newInstance->i = i;
379 return newInstance;
380}
381
382-(id)mutableCopyWithZone:(NSZone *)zone {
383 ClassWithCopyWithZone *newInstance = [[ClassWithCopyWithZone alloc] init];
384 if (newInstance) {
385 newInstance->i = i;
386 }
387
388 return newInstance;
389}
Devin Coughlin4a330202016-01-22 01:01:11 +0000390@end
Devin Coughlina1d9d752016-03-05 01:32:43 +0000391
392NSString * _Nullable returnsNullableString();
393
394void callFunctionInSystemHeader() {
395 NSString *s = returnsNullableString();
396
397 NSSystemFunctionTakingNonnull(s);
398 #if !NOSYSTEMHEADERS
399 // expected-warning@-2{{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
400 #endif
401}
402
403void callMethodInSystemHeader() {
404 NSString *s = returnsNullableString();
405
406 NSSystemClass *sc = [[NSSystemClass alloc] init];
407 [sc takesNonnull:s];
408 #if !NOSYSTEMHEADERS
409 // expected-warning@-2{{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
410 #endif
411}