Home | History | Annotate | Download | only in Analysis
      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 
     16 TestObject * getUnspecifiedTestObject();
     17 TestObject *_Nonnull getNonnullTestObject();
     18 TestObject *_Nullable getNullableTestObject();
     19 
     20 int getRandom();
     21 
     22 typedef struct Dummy { int val; } Dummy;
     23 
     24 void takesNullable(Dummy *_Nullable);
     25 void takesNonnull(Dummy *_Nonnull);
     26 void takesUnspecified(Dummy *);
     27 
     28 Dummy *_Nullable returnsNullable();
     29 Dummy *_Nonnull returnsNonnull();
     30 Dummy *returnsUnspecified();
     31 int *_Nullable returnsNullableInt();
     32 
     33 template <typename T> T *eraseNullab(T *p) { return p; }
     34 
     35 void takesAttrNonnull(Dummy *p) __attribute((nonnull(1)));
     36 
     37 void 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 
     84 void testMultiParamChecking(Dummy *_Nonnull a, Dummy *_Nullable b,
     85                             Dummy *_Nonnull c);
     86 
     87 void 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 
    103 Dummy *_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 
    108 Dummy *_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 
    113 void 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 
    154 Dummy * _Nonnull testDirectCastNullableToNonnull() {
    155   Dummy *p = returnsNullable();
    156   takesNonnull((Dummy * _Nonnull)p);  // no-warning
    157   return (Dummy * _Nonnull)p;         // no-warning
    158 }
    159 
    160 Dummy * _Nonnull testIndirectCastNullableToNonnull() {
    161   Dummy *p = (Dummy * _Nonnull)returnsNullable();
    162   takesNonnull(p);  // no-warning
    163   return p;         // no-warning
    164 }
    165 
    166 Dummy * _Nonnull testDirectCastNilToNonnull() {
    167   takesNonnull((Dummy * _Nonnull)0);  // no-warning
    168   return (Dummy * _Nonnull)0;         // no-warning
    169 }
    170 
    171 void 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 
    177 void 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 
    188 void 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 
    199 void 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 
    218 void testIndirectNilPassToNonnull() {
    219   Dummy *p = 0;
    220   takesNonnull(p);  // expected-warning {{Null passed to a callee that requires a non-null 1st parameter}}
    221 }
    222 
    223 void 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 
    229 Dummy * _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 
    235 void testInvalidPropagation() {
    236   Dummy *p = returnsUnspecified();
    237   takesNullable(p);
    238   takesNonnull(p);
    239 }
    240 
    241 void 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 
    251 Dummy *_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 
    265 Dummy *_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 
    278 void 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 
    300 int * _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 
    308 int * _Nonnull InlinedReturnNullOverSuppressionCallee(int * _Nonnull p2) {
    309   int *result = 0;
    310   return result; // no-warning; but this is an over suppression
    311 }
    312 
    313 int *InlinedReturnNullOverSuppressionCaller(int * _Nonnull p1) {
    314   return InlinedReturnNullOverSuppressionCallee(p1);
    315 }
    316 
    317 void inlinedNullable(Dummy *_Nullable p) {
    318   if (p) return;
    319 }
    320 void inlinedNonnull(Dummy *_Nonnull p) {
    321   if (p) return;
    322 }
    323 void inlinedUnspecified(Dummy *p) {
    324   if (p) return;
    325 }
    326 
    327 void 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 
    335 Dummy *_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 
    468 NSString * _Nullable returnsNullableString();
    469 
    470 void 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 
    479 void 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