• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// 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
3
4#include "Inputs/system-header-simulator-for-nullability.h"
5
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
35void takesAttrNonnull(Dummy *p) __attribute((nonnull(1)));
36
37void 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: {
43    Dummy &r = *p; // expected-warning {{Nullable pointer is dereferenced}}
44  } break;
45  case 1: {
46    int b = p->val; // expected-warning {{Nullable pointer is dereferenced}}
47  } break;
48  case 2: {
49    int stuff = *ptr; // expected-warning {{Nullable pointer is dereferenced}}
50  } break;
51  case 3:
52    takesNonnull(p); // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
53    break;
54  case 4: {
55    Dummy d;
56    takesNullable(&d);
57    Dummy dd(d);
58    break;
59  }
60  case 5: takesAttrNonnull(p); break; // expected-warning {{Nullable pointer is passed to}}
61  default: { Dummy d = *p; } break; // expected-warning {{Nullable pointer is dereferenced}}
62  }
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);
74    takesNonnull(q); // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}
75  }
76  Dummy a;
77  Dummy *_Nonnull nonnull = &a;
78  nonnull = q; // expected-warning {{Null is assigned to a pointer which is expected to have non-null value}}
79  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()) {
91  case 1: nonnull = p; break; // expected-warning {{Nullable pointer is assigned to a pointer which is expected to have non-null value}}
92  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;
96  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}}
99  case 9: testMultiParamChecking((Dummy *_Nonnull)0, nullable, nonnull); break;
100  }
101}
102
103Dummy *_Nonnull testNullableReturn(Dummy *_Nullable a) {
104  Dummy *p = a;
105  return p; // expected-warning {{Nullable pointer is returned from a function that is expected to return a non-null value}}
106}
107
108Dummy *_Nonnull testNullReturn() {
109  Dummy *p = 0;
110  return p; // expected-warning {{Null is returned from a function that is expected to return a non-null value}}
111}
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];
132    [o takesNonnull:shouldBeNullable]; // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
133    break;
134  case 4:
135    shouldBeNullable = [eraseNullab(getNonnullTestObject()) returnsNullable];
136    [o takesNonnull:shouldBeNullable]; // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
137    break;
138  case 5:
139    shouldBeNullable =
140        [eraseNullab(getUnspecifiedTestObject()) returnsNullable];
141    [o takesNonnull:shouldBeNullable]; // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
142    break;
143  case 6:
144    shouldBeNullable = [eraseNullab(getNullableTestObject()) returnsNullable];
145    [o takesNonnull:shouldBeNullable]; // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
146    break;
147  case 7: {
148    int *shouldBeNonnull = [eraseNullab(getNonnullTestObject()) returnsNonnull];
149    [o takesNonnull:shouldBeNonnull];
150  } break;
151  }
152}
153
154Dummy * _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() {
161  Dummy *p = (Dummy * _Nonnull)returnsNullable();
162  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.
174  takesNonnull(p);  // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}
175}
176
177void 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
218void 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  }
227}
228
229Dummy * _Nonnull testIndirectCastNilToNonnullAndReturn() {
230  Dummy *p = (Dummy * _Nonnull)0;
231  // FIXME: Ideally the cast above would suppress this warning.
232  return p; // expected-warning {{Null is returned from a function that is expected to return a non-null value}}
233}
234
235void testInvalidPropagation() {
236  Dummy *p = returnsUnspecified();
237  takesNullable(p);
238  takesNonnull(p);
239}
240
241void onlyReportFirstPreconditionViolationOnPath() {
242  Dummy *p = returnsNullable();
243  takesNonnull(p); // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
244  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
282@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
317void 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
327void 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
335Dummy *_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())
342    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
356  return p;
357}
358
359
360@interface SomeClass : NSObject {
361  int instanceVar;
362}
363@end
364
365@implementation SomeClass (MethodReturn)
366- (id)initWithSomething:(int)i {
367  if (self = [super init]) {
368    instanceVar = i;
369  }
370
371  return self;
372}
373
374- (TestObject * _Nonnull)testReturnsNullableInNonnullIndirectly {
375  TestObject *local = getNullableTestObject();
376  return local; // expected-warning {{Nullable pointer is returned from a method that is expected to return a non-null value}}
377}
378
379- (TestObject * _Nonnull)testReturnsCastSuppressedNullableInNonnullIndirectly {
380  TestObject *local = getNullableTestObject();
381  return (TestObject * _Nonnull)local; // no-warning
382}
383
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
392
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;
411  // False negative. Once we have more subtle suppression of defensive checks in
412  // initializers we should warn here.
413  return other;
414}
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}
430
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}
466@end
467
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}
488
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 {
523  _nilledOutInternal = (id _Nonnull)nil;
524
525  return nil; // no-warning
526}
527@end
528