• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// RUN: %clang_analyze_cc1 -fblocks -verify %s -analyzer-checker=core \
2// RUN:   -analyzer-checker=nullability.NullPassedToNonnull \
3// RUN:   -analyzer-checker=nullability.NullReturnedFromNonnull \
4// RUN:   -analyzer-checker=nullability.NullablePassedToNonnull \
5// RUN:   -analyzer-checker=nullability.NullableReturnedFromNonnull \
6// RUN:   -analyzer-checker=nullability.NullableDereferenced \
7// RUN:   -DNOSYSTEMHEADERS=0
8
9// RUN: %clang_analyze_cc1 -fblocks -verify %s -analyzer-checker=core \
10// RUN:   -analyzer-checker=nullability.NullPassedToNonnull \
11// RUN:   -analyzer-checker=nullability.NullReturnedFromNonnull \
12// RUN:   -analyzer-checker=nullability.NullablePassedToNonnull \
13// RUN:   -analyzer-checker=nullability.NullableReturnedFromNonnull \
14// RUN:   -analyzer-checker=nullability.NullableDereferenced \
15// RUN:   -DNOSYSTEMHEADERS=1 \
16// RUN:   -analyzer-config nullability:NoDiagnoseCallsToSystemHeaders=true
17
18// RUN: %clang_analyze_cc1 -fblocks -verify %s -analyzer-checker=core\
19// RUN:   -analyzer-checker=nullability.NullPassedToNonnull\
20// RUN:   -analyzer-checker=nullability.NullReturnedFromNonnull\
21// RUN:   -analyzer-checker=nullability.NullablePassedToNonnull\
22// RUN:   -analyzer-checker=nullability.NullableReturnedFromNonnull\
23// RUN:   -analyzer-checker=nullability.NullableDereferenced\
24// RUN:   -DNOSYSTEMHEADERS=0 -fobjc-arc
25
26// RUN: %clang_analyze_cc1 -fblocks -verify %s -analyzer-checker=core\
27// RUN:   -analyzer-checker=nullability.NullPassedToNonnull\
28// RUN:   -analyzer-checker=nullability.NullReturnedFromNonnull\
29// RUN:   -analyzer-checker=nullability.NullablePassedToNonnull\
30// RUN:   -analyzer-checker=nullability.NullableReturnedFromNonnull\
31// RUN:   -analyzer-checker=nullability.NullableDereferenced\
32// RUN:   -DNOSYSTEMHEADERS=1 -fobjc-arc\
33// RUN:   -analyzer-config nullability:NoDiagnoseCallsToSystemHeaders=true
34
35#include "Inputs/system-header-simulator-for-nullability.h"
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
66void takesAttrNonnull(Dummy *p) __attribute((nonnull(1)));
67
68void 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: {
74    Dummy &r = *p; // expected-warning {{Nullable pointer is dereferenced}}
75  } break;
76  case 1: {
77    int b = p->val; // expected-warning {{Nullable pointer is dereferenced}}
78  } break;
79  case 2: {
80    int stuff = *ptr; // expected-warning {{Nullable pointer is dereferenced}}
81  } break;
82  case 3:
83    takesNonnull(p); // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
84    break;
85  case 4: {
86    Dummy d;
87    takesNullable(&d);
88    Dummy dd(d);
89    break;
90  }
91  case 5: takesAttrNonnull(p); break; // expected-warning {{Nullable pointer is passed to}}
92  default: { Dummy d = *p; } break; // expected-warning {{Nullable pointer is dereferenced}}
93  }
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);
105    takesNonnull(q); // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}
106  }
107  Dummy a;
108  Dummy *_Nonnull nonnull = &a;
109  nonnull = q; // expected-warning {{Null assigned to a pointer which is expected to have non-null value}}
110  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()) {
122  case 1: nonnull = p; break; // expected-warning {{Nullable pointer is assigned to a pointer which is expected to have non-null value}}
123  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;
127  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}}
130  case 9: testMultiParamChecking((Dummy *_Nonnull)0, nullable, nonnull); break;
131  }
132}
133
134Dummy *_Nonnull testNullableReturn(Dummy *_Nullable a) {
135  Dummy *p = a;
136  return p; // expected-warning {{Nullable pointer is returned from a function that is expected to return a non-null value}}
137}
138
139Dummy *_Nonnull testNullReturn() {
140  Dummy *p = 0;
141  return p; // expected-warning {{Null returned from a function that is expected to return a non-null value}}
142}
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];
163    [o takesNonnull:shouldBeNullable]; // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
164    break;
165  case 4:
166    shouldBeNullable = [eraseNullab(getNonnullTestObject()) returnsNullable];
167    [o takesNonnull:shouldBeNullable]; // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
168    break;
169  case 5:
170    shouldBeNullable =
171        [eraseNullab(getUnspecifiedTestObject()) returnsNullable];
172    [o takesNonnull:shouldBeNullable]; // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
173    break;
174  case 6:
175    shouldBeNullable = [eraseNullab(getNullableTestObject()) returnsNullable];
176    [o takesNonnull:shouldBeNullable]; // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
177    break;
178  case 7: {
179    int *shouldBeNonnull = [eraseNullab(getNonnullTestObject()) returnsNonnull];
180    [o takesNonnull:shouldBeNonnull];
181  } break;
182  }
183}
184
185Dummy * _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() {
192  Dummy *p = (Dummy * _Nonnull)returnsNullable();
193  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.
205  takesNonnull(p);  // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}
206}
207
208void testDirectCastNilToNonnullAndAssignToLocalInInitializer() {
209  Dummy * _Nonnull nonnullLocalWithAssignmentInInitializer = (Dummy * _Nonnull)0; // no-warning
210  (void)nonnullLocalWithAssignmentInInitializer;
211
212  // Since we've already had an invariant violation along this path,
213  // we shouldn't warn here.
214  nonnullLocalWithAssignmentInInitializer = 0;
215  (void)nonnullLocalWithAssignmentInInitializer;
216
217}
218
219void testDirectCastNilToNonnullAndAssignToLocal(Dummy * _Nonnull p) {
220  Dummy * _Nonnull nonnullLocalWithAssignment = p;
221  nonnullLocalWithAssignment = (Dummy * _Nonnull)0; // no-warning
222  (void)nonnullLocalWithAssignment;
223
224  // Since we've already had an invariant violation along this path,
225  // we shouldn't warn here.
226  nonnullLocalWithAssignment = 0;
227  (void)nonnullLocalWithAssignment;
228}
229
230void testDirectCastNilToNonnullAndAssignToParam(Dummy * _Nonnull p) {
231  p = (Dummy * _Nonnull)0; // no-warning
232}
233
234@interface ClassWithNonnullIvar : NSObject {
235  Dummy *_nonnullIvar;
236}
237@end
238
239@implementation ClassWithNonnullIvar
240-(void)testDirectCastNilToNonnullAndAssignToIvar {
241  _nonnullIvar = (Dummy * _Nonnull)0; // no-warning;
242
243  // Since we've already had an invariant violation along this path,
244  // we shouldn't warn here.
245  _nonnullIvar = 0;
246}
247@end
248
249void testIndirectNilPassToNonnull() {
250  Dummy *p = 0;
251  takesNonnull(p);  // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}
252}
253
254void testConditionalNilPassToNonnull(Dummy *p) {
255  if (!p) {
256    takesNonnull(p);  // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}
257  }
258}
259
260Dummy * _Nonnull testIndirectCastNilToNonnullAndReturn() {
261  Dummy *p = (Dummy * _Nonnull)0;
262  // FIXME: Ideally the cast above would suppress this warning.
263  return p; // expected-warning {{Null returned from a function that is expected to return a non-null value}}
264}
265
266void testInvalidPropagation() {
267  Dummy *p = returnsUnspecified();
268  takesNullable(p);
269  takesNonnull(p);
270}
271
272void onlyReportFirstPreconditionViolationOnPath() {
273  Dummy *p = returnsNullable();
274  takesNonnull(p); // expected-warning {{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
275  takesNonnull(p); // No warning.
276  // The first warning was not a sink. The analysis expected to continue.
277  int i = 0;
278  i = 5 / i; // expected-warning {{Division by zero}}
279  (void)i;
280}
281
282Dummy *_Nonnull doNotWarnWhenPreconditionIsViolatedInTopFunc(
283    Dummy *_Nonnull p) {
284  if (!p) {
285    Dummy *ret =
286        0; // avoid compiler warning (which is not generated by the analyzer)
287    if (getRandom())
288      return ret; // no warning
289    else
290      return p; // no warning
291  } else {
292    return p;
293  }
294}
295
296Dummy *_Nonnull doNotWarnWhenPreconditionIsViolated(Dummy *_Nonnull p) {
297  if (!p) {
298    Dummy *ret =
299        0; // avoid compiler warning (which is not generated by the analyzer)
300    if (getRandom())
301      return ret; // no warning
302    else
303      return p; // no warning
304  } else {
305    return p;
306  }
307}
308
309void testPreconditionViolationInInlinedFunction(Dummy *p) {
310  doNotWarnWhenPreconditionIsViolated(p);
311}
312
313@interface TestInlinedPreconditionViolationClass : NSObject
314@end
315
316@implementation TestInlinedPreconditionViolationClass
317-(Dummy * _Nonnull) calleeWithParam:(Dummy * _Nonnull) p2 {
318  Dummy *x = 0;
319  if (!p2) // p2 binding becomes dead at this point.
320    return x; // no-warning
321  else
322   return p2;
323}
324
325-(Dummy *)callerWithParam:(Dummy * _Nonnull) p1 {
326  return [self calleeWithParam:p1];
327}
328
329@end
330
331int * _Nonnull InlinedPreconditionViolationInFunctionCallee(int * _Nonnull p2) {
332  int *x = 0;
333  if (!p2) // p2 binding becomes dead at this point.
334    return x; // no-warning
335  else
336   return p2;
337}
338
339int * _Nonnull InlinedReturnNullOverSuppressionCallee(int * _Nonnull p2) {
340  int *result = 0;
341  return result; // no-warning; but this is an over suppression
342}
343
344int *InlinedReturnNullOverSuppressionCaller(int * _Nonnull p1) {
345  return InlinedReturnNullOverSuppressionCallee(p1);
346}
347
348void inlinedNullable(Dummy *_Nullable p) {
349  if (p) return;
350}
351void inlinedNonnull(Dummy *_Nonnull p) {
352  if (p) return;
353}
354void inlinedUnspecified(Dummy *p) {
355  if (p) return;
356}
357
358void testNilReturnWithBlock(Dummy *p) {
359  p = 0;
360  Dummy *_Nonnull (^myblock)(void) = ^Dummy *_Nonnull(void) {
361    return p; // TODO: We should warn in blocks.
362  };
363  myblock();
364}
365
366Dummy *_Nonnull testDefensiveInlineChecks(Dummy * p) {
367  switch (getRandom()) {
368  case 1: inlinedNullable(p); break;
369  case 2: inlinedNonnull(p); break;
370  case 3: inlinedUnspecified(p); break;
371  }
372  if (getRandom())
373    takesNonnull(p);  // no-warning
374
375  if (getRandom()) {
376    Dummy *_Nonnull varWithInitializer = p; // no-warning
377
378     Dummy *_Nonnull var1WithInitializer = p,  // no-warning
379           *_Nonnull var2WithInitializer = p;  // no-warning
380  }
381
382  if (getRandom()) {
383    Dummy *_Nonnull varWithoutInitializer;
384    varWithoutInitializer = p; // no-warning
385  }
386
387  return p;
388}
389
390
391@interface SomeClass : NSObject {
392  int instanceVar;
393}
394@end
395
396@implementation SomeClass (MethodReturn)
397- (id)initWithSomething:(int)i {
398  if (self = [super init]) {
399    instanceVar = i;
400  }
401
402  return self;
403}
404
405- (TestObject * _Nonnull)testReturnsNullableInNonnullIndirectly {
406  TestObject *local = getNullableTestObject();
407  return local; // expected-warning {{Nullable pointer is returned from a method that is expected to return a non-null value}}
408}
409
410- (TestObject * _Nonnull)testReturnsCastSuppressedNullableInNonnullIndirectly {
411  TestObject *local = getNullableTestObject();
412  return (TestObject * _Nonnull)local; // no-warning
413}
414
415- (TestObject * _Nonnull)testReturnsNullableInNonnullWhenPreconditionViolated:(TestObject * _Nonnull) p {
416  TestObject *local = getNullableTestObject();
417  if (!p) // Pre-condition violated here.
418    return local; // no-warning
419  else
420    return p; // no-warning
421}
422@end
423
424@interface ClassWithInitializers : NSObject
425@end
426
427@implementation ClassWithInitializers
428- (instancetype _Nonnull)initWithNonnullReturnAndSelfCheckingIdiom {
429  // This defensive check is a common-enough idiom that we filter don't want
430  // to issue a diagnostic for it,
431  if (self = [super init]) {
432  }
433
434  return self; // no-warning
435}
436
437- (instancetype _Nonnull)initWithNonnullReturnAndNilReturnViaLocal {
438  self = [super init];
439  // This leaks, but we're not checking for that here.
440
441  ClassWithInitializers *other = nil;
442  // False negative. Once we have more subtle suppression of defensive checks in
443  // initializers we should warn here.
444  return other;
445}
446@end
447
448@interface SubClassWithInitializers : ClassWithInitializers
449@end
450
451@implementation SubClassWithInitializers
452// Note: Because this is overriding
453// -[ClassWithInitializers initWithNonnullReturnAndSelfCheckingIdiom],
454// the return type of this method becomes implicitly id _Nonnull.
455- (id)initWithNonnullReturnAndSelfCheckingIdiom {
456  if (self = [super initWithNonnullReturnAndSelfCheckingIdiom]) {
457  }
458
459  return self; // no-warning
460}
461
462- (id _Nonnull)initWithNonnullReturnAndSelfCheckingIdiomV2; {
463  // Another common return-checking idiom
464  self = [super initWithNonnullReturnAndSelfCheckingIdiom];
465  if (!self) {
466    return nil; // no-warning
467  }
468
469  return self;
470}
471@end
472
473@interface ClassWithCopyWithZone : NSObject<NSCopying,NSMutableCopying> {
474  id i;
475}
476
477@end
478
479@implementation ClassWithCopyWithZone
480-(id)copyWithZone:(NSZone *)zone {
481  ClassWithCopyWithZone *newInstance = [[ClassWithCopyWithZone alloc] init];
482  if (!newInstance)
483    return nil;
484
485  newInstance->i = i;
486  return newInstance;
487}
488
489-(id)mutableCopyWithZone:(NSZone *)zone {
490  ClassWithCopyWithZone *newInstance = [[ClassWithCopyWithZone alloc] init];
491  if (newInstance) {
492    newInstance->i = i;
493  }
494
495  return newInstance;
496}
497@end
498
499NSString * _Nullable returnsNullableString();
500
501void callFunctionInSystemHeader() {
502  NSString *s = returnsNullableString();
503
504  NSSystemFunctionTakingNonnull(s);
505  #if !NOSYSTEMHEADERS
506  // expected-warning@-2{{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
507  #endif
508}
509
510void callMethodInSystemHeader() {
511  NSString *s = returnsNullableString();
512
513  NSSystemClass *sc = [[NSSystemClass alloc] init];
514  [sc takesNonnull:s];
515  #if !NOSYSTEMHEADERS
516  // expected-warning@-2{{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
517  #endif
518}
519
520// Test to make sure the analyzer doesn't warn when an a nullability invariant
521// has already been found to be violated on an instance variable.
522
523@class MyInternalClass;
524@interface MyClass : NSObject {
525  MyInternalClass * _Nonnull _internal;
526}
527@end
528
529@interface MyInternalClass : NSObject {
530  @public
531  id _someIvar;
532}
533-(id _Nonnull)methodWithInternalImplementation;
534@end
535
536@interface MyClass () {
537  MyInternalClass * _Nonnull _nilledOutInternal;
538}
539@end
540
541@implementation MyClass
542-(id _Nonnull)methodWithInternalImplementation {
543  if (!_internal)
544    return nil; // no-warning
545
546  return [_internal methodWithInternalImplementation];
547}
548
549- (id _Nonnull)methodReturningIvarInImplementation; {
550  return _internal == 0 ? nil : _internal->_someIvar; // no-warning
551}
552
553-(id _Nonnull)methodWithNilledOutInternal {
554  _nilledOutInternal = (id _Nonnull)nil;
555
556  return nil; // no-warning
557}
558@end
559