Home | History | Annotate | Download | only in Analysis
      1 // RUN: %clang_cc1 -analyze -analyzer-checker=core,nullability -verify %s
      2 
      3 #define nil 0
      4 #define BOOL int
      5 
      6 @protocol NSObject
      7 + (id)alloc;
      8 - (id)init;
      9 @end
     10 
     11 @protocol NSCopying
     12 @end
     13 
     14 __attribute__((objc_root_class))
     15 @interface
     16 NSObject<NSObject>
     17 @end
     18 
     19 @interface NSString : NSObject<NSCopying>
     20 - (BOOL)isEqualToString : (NSString *_Nonnull)aString;
     21 - (NSString *)stringByAppendingString:(NSString *_Nonnull)aString;
     22 @end
     23 
     24 @interface TestObject : NSObject
     25 - (int *_Nonnull)returnsNonnull;
     26 - (int *_Nullable)returnsNullable;
     27 - (int *)returnsUnspecified;
     28 - (void)takesNonnull:(int *_Nonnull)p;
     29 - (void)takesNullable:(int *_Nullable)p;
     30 - (void)takesUnspecified:(int *)p;
     31 @property(readonly, strong) NSString *stuff;
     32 @end
     33 
     34 TestObject * getUnspecifiedTestObject();
     35 TestObject *_Nonnull getNonnullTestObject();
     36 TestObject *_Nullable getNullableTestObject();
     37 
     38 int getRandom();
     39 
     40 typedef struct Dummy { int val; } Dummy;
     41 
     42 void takesNullable(Dummy *_Nullable);
     43 void takesNonnull(Dummy *_Nonnull);
     44 void takesUnspecified(Dummy *);
     45 
     46 Dummy *_Nullable returnsNullable();
     47 Dummy *_Nonnull returnsNonnull();
     48 Dummy *returnsUnspecified();
     49 int *_Nullable returnsNullableInt();
     50 
     51 template <typename T> T *eraseNullab(T *p) { return p; }
     52 
     53 void takesAttrNonnull(Dummy *p) __attribute((nonnull(1)));
     54 
     55 void testBasicRules() {
     56   Dummy *p = returnsNullable();
     57   int *ptr = returnsNullableInt();
     58   // Make every dereference a different path to avoid sinks after errors.
     59   switch (getRandom()) {
     60   case 0: {
     61     Dummy &r = *p; // expected-warning {{}}
     62   } break;
     63   case 1: {
     64     int b = p->val; // expected-warning {{}}
     65   } break;
     66   case 2: {
     67     int stuff = *ptr; // expected-warning {{}}
     68   } break;
     69   case 3:
     70     takesNonnull(p); // expected-warning {{}}
     71     break;
     72   case 4: {
     73     Dummy d;
     74     takesNullable(&d);
     75     Dummy dd(d);
     76     break;
     77   }
     78   case 5: takesAttrNonnull(p); break; // expected-warning {{Nullable pointer is passed to}}
     79   default: { Dummy d = *p; } break; // expected-warning {{Nullable pointer is dereferenced}}
     80   }
     81   if (p) {
     82     takesNonnull(p);
     83     if (getRandom()) {
     84       Dummy &r = *p;
     85     } else {
     86       int b = p->val;
     87     }
     88   }
     89   Dummy *q = 0;
     90   if (getRandom()) {
     91     takesNullable(q);
     92     takesNonnull(q); // expected-warning {{}}
     93   }
     94   Dummy a;
     95   Dummy *_Nonnull nonnull = &a;
     96   nonnull = q; // expected-warning {{}}
     97   q = &a;
     98   takesNullable(q);
     99   takesNonnull(q);
    100 }
    101 
    102 void testMultiParamChecking(Dummy *_Nonnull a, Dummy *_Nullable b,
    103                             Dummy *_Nonnull c);
    104 
    105 void testArgumentTracking(Dummy *_Nonnull nonnull, Dummy *_Nullable nullable) {
    106   Dummy *p = nullable;
    107   Dummy *q = nonnull;
    108   switch(getRandom()) {
    109   case 1: nonnull = p; break; // expected-warning {{}}
    110   case 2: p = 0; break;
    111   case 3: q = p; break;
    112   case 4: testMultiParamChecking(nonnull, nullable, nonnull); break;
    113   case 5: testMultiParamChecking(nonnull, nonnull, nonnull); break;
    114   case 6: testMultiParamChecking(nonnull, nullable, nullable); break; // expected-warning {{}}
    115   case 7: testMultiParamChecking(nullable, nullable, nonnull); // expected-warning {{}}
    116   case 8: testMultiParamChecking(nullable, nullable, nullable); // expected-warning {{}}
    117   case 9: testMultiParamChecking((Dummy *_Nonnull)0, nullable, nonnull); break;
    118   }
    119 }
    120 
    121 Dummy *_Nonnull testNullableReturn(Dummy *_Nullable a) {
    122   Dummy *p = a;
    123   return p; // expected-warning {{}}
    124 }
    125 
    126 Dummy *_Nonnull testNullReturn() {
    127   Dummy *p = 0;
    128   return p; // expected-warning {{}}
    129 }
    130 
    131 void testObjCMessageResultNullability() {
    132   // The expected result: the most nullable of self and method return type.
    133   TestObject *o = getUnspecifiedTestObject();
    134   int *shouldBeNullable = [eraseNullab(getNullableTestObject()) returnsNonnull];
    135   switch (getRandom()) {
    136   case 0:
    137     // The core analyzer assumes that the receiver is non-null after a message
    138     // send. This is to avoid some false positives, and increase performance
    139     // but it also reduces the coverage and makes this checker unable to reason
    140     // about the nullness of the receiver. 
    141     [o takesNonnull:shouldBeNullable]; // No warning expected.
    142     break;
    143   case 1:
    144     shouldBeNullable =
    145         [eraseNullab(getNullableTestObject()) returnsUnspecified];
    146     [o takesNonnull:shouldBeNullable]; // No warning expected.
    147     break;
    148   case 3:
    149     shouldBeNullable = [eraseNullab(getNullableTestObject()) returnsNullable];
    150     [o takesNonnull:shouldBeNullable]; // expected-warning {{}}
    151     break;
    152   case 4:
    153     shouldBeNullable = [eraseNullab(getNonnullTestObject()) returnsNullable];
    154     [o takesNonnull:shouldBeNullable]; // expected-warning {{}}
    155     break;
    156   case 5:
    157     shouldBeNullable =
    158         [eraseNullab(getUnspecifiedTestObject()) returnsNullable];
    159     [o takesNonnull:shouldBeNullable]; // expected-warning {{}}
    160     break;
    161   case 6:
    162     shouldBeNullable = [eraseNullab(getNullableTestObject()) returnsNullable];
    163     [o takesNonnull:shouldBeNullable]; // expected-warning {{}}
    164     break;
    165   case 7: {
    166     int *shouldBeNonnull = [eraseNullab(getNonnullTestObject()) returnsNonnull];
    167     [o takesNonnull:shouldBeNonnull];
    168   } break;
    169   }
    170 }
    171 
    172 void testCast() {
    173   Dummy *p = (Dummy * _Nonnull)returnsNullable();
    174   takesNonnull(p);
    175 }
    176 
    177 void testInvalidPropagation() {
    178   Dummy *p = returnsUnspecified();
    179   takesNullable(p);
    180   takesNonnull(p);
    181 }
    182 
    183 void onlyReportFirstPreconditionViolationOnPath() {
    184   Dummy *p = returnsNullable();
    185   takesNonnull(p); // expected-warning {{}}
    186   takesNonnull(p); // No warning.
    187   // The first warning was not a sink. The analysis expected to continue.
    188   int i = 0;
    189   i = 5 / i; // expected-warning {{Division by zero}}
    190   (void)i;
    191 }
    192 
    193 Dummy *_Nonnull doNotWarnWhenPreconditionIsViolatedInTopFunc(
    194     Dummy *_Nonnull p) {
    195   if (!p) {
    196     Dummy *ret =
    197         0; // avoid compiler warning (which is not generated by the analyzer)
    198     if (getRandom())
    199       return ret; // no warning
    200     else
    201       return p; // no warning
    202   } else {
    203     return p;
    204   }
    205 }
    206 
    207 Dummy *_Nonnull doNotWarnWhenPreconditionIsViolated(Dummy *_Nonnull p) {
    208   if (!p) {
    209     Dummy *ret =
    210         0; // avoid compiler warning (which is not generated by the analyzer)
    211     if (getRandom())
    212       return ret; // no warning
    213     else
    214       return p; // no warning
    215   } else {
    216     return p;
    217   }
    218 }
    219 
    220 void testPreconditionViolationInInlinedFunction(Dummy *p) {
    221   doNotWarnWhenPreconditionIsViolated(p);
    222 }
    223 
    224 void inlinedNullable(Dummy *_Nullable p) {
    225   if (p) return;
    226 }
    227 void inlinedNonnull(Dummy *_Nonnull p) {
    228   if (p) return;
    229 }
    230 void inlinedUnspecified(Dummy *p) {
    231   if (p) return;
    232 }
    233 
    234 Dummy *_Nonnull testDefensiveInlineChecks(Dummy * p) {
    235   switch (getRandom()) {
    236   case 1: inlinedNullable(p); break;
    237   case 2: inlinedNonnull(p); break;
    238   case 3: inlinedUnspecified(p); break;
    239   }
    240   if (getRandom())
    241     takesNonnull(p);  // no-warning
    242 
    243   if (getRandom()) {
    244     Dummy *_Nonnull varWithInitializer = p; // no-warning
    245 
    246      Dummy *_Nonnull var1WithInitializer = p,  // no-warning
    247            *_Nonnull var2WithInitializer = p;  // no-warning
    248   }
    249 
    250   if (getRandom()) {
    251     Dummy *_Nonnull varWithoutInitializer;
    252     varWithoutInitializer = p; // no-warning
    253   }
    254 
    255   return p;
    256 }
    257