Home | History | Annotate | Download | only in Analysis
      1 // RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.Loops,debug.ExprInspection -verify %s
      2 
      3 void clang_analyzer_eval(int);
      4 
      5 #define nil ((id)0)
      6 
      7 typedef unsigned long NSUInteger;
      8 @protocol NSFastEnumeration
      9 - (int)countByEnumeratingWithState:(void *)state objects:(id *)objects count:(unsigned)count;
     10 - (void)protocolMethod;
     11 @end
     12 
     13 @interface NSObject
     14 + (instancetype)testObject;
     15 @end
     16 
     17 @interface NSEnumerator <NSFastEnumeration>
     18 @end
     19 
     20 @interface NSArray : NSObject <NSFastEnumeration>
     21 - (NSUInteger)count;
     22 - (NSEnumerator *)objectEnumerator;
     23 @end
     24 
     25 @interface NSDictionary : NSObject <NSFastEnumeration>
     26 - (NSUInteger)count;
     27 - (id)objectForKey:(id)key;
     28 @end
     29 
     30 @interface NSDictionary (SomeCategory)
     31 - (void)categoryMethodOnNSDictionary;
     32 @end
     33 
     34 @interface NSMutableDictionary : NSDictionary
     35 - (void)setObject:(id)obj forKey:(id)key;
     36 @end
     37 
     38 @interface NSMutableArray : NSArray
     39 - (void)addObject:(id)obj;
     40 @end
     41 
     42 @interface NSSet : NSObject <NSFastEnumeration>
     43 - (NSUInteger)count;
     44 @end
     45 
     46 @interface NSPointerArray : NSObject <NSFastEnumeration>
     47 @end
     48 
     49 @interface NSString : NSObject
     50 @end
     51 
     52 void test() {
     53   id x;
     54   for (x in [NSArray testObject])
     55     clang_analyzer_eval(x != nil); // expected-warning{{TRUE}}
     56 
     57   for (x in [NSMutableDictionary testObject])
     58     clang_analyzer_eval(x != nil); // expected-warning{{TRUE}}
     59 
     60   for (x in [NSSet testObject])
     61     clang_analyzer_eval(x != nil); // expected-warning{{TRUE}}
     62 
     63   for (x in [[NSArray testObject] objectEnumerator])
     64     clang_analyzer_eval(x != nil); // expected-warning{{TRUE}}
     65 
     66   for (x in [NSPointerArray testObject])
     67     clang_analyzer_eval(x != nil); // expected-warning{{UNKNOWN}}
     68 }
     69 
     70 void testWithVarInFor() {
     71   for (id x in [NSArray testObject])
     72     clang_analyzer_eval(x != nil); // expected-warning{{TRUE}}
     73   for (id x in [NSPointerArray testObject])
     74     clang_analyzer_eval(x != nil); // expected-warning{{UNKNOWN}}
     75 }
     76 
     77 void testNonNil(id a, id b) {
     78   clang_analyzer_eval(a != nil); // expected-warning{{UNKNOWN}}
     79   for (id x in a)
     80     clang_analyzer_eval(a != nil); // expected-warning{{TRUE}}
     81 
     82   if (b != nil)
     83     return;
     84   for (id x in b)
     85     *(volatile int *)0 = 1; // no-warning
     86   clang_analyzer_eval(b != nil); // expected-warning{{FALSE}}
     87 }
     88 
     89 void collectionIsEmpty(NSMutableDictionary *D){
     90   if ([D count] == 0) { // Count is zero.
     91     NSString *s = 0;
     92     for (NSString *key in D) {
     93       s = key;       // Loop is never entered.
     94     }
     95     clang_analyzer_eval(s == 0); //expected-warning{{TRUE}}
     96   }
     97 }
     98 
     99 void processCollection(NSMutableDictionary *D);
    100 void collectionIsEmptyCollectionIsModified(NSMutableDictionary *D){
    101   if ([D count] == 0) {      // Count is zero.
    102     NSString *s = 0;
    103     processCollection(D);  // However, the collection has changed.
    104     for (NSString *key in D) {
    105       s = key;       // Loop might be entered.
    106     }
    107     clang_analyzer_eval(s == 0); //expected-warning{{FALSE}} //expected-warning{{TRUE}}
    108   }
    109 }
    110 
    111 int collectionIsEmptyNSSet(NSSet *S){
    112   if ([S count] == 2) { // Count is non-zero.
    113     int tapCounts[2];
    114     int i = 0;
    115     for (NSString *elem in S) {
    116       tapCounts[i]= 1;       // Loop is entered.
    117       i++;
    118     }
    119     return (tapCounts[0]); //no warning
    120   }
    121   return 0;
    122 }
    123 
    124 int collectionIsNotEmptyNSArray(NSArray *A) {
    125   int count = [A count];
    126   if (count > 0) {
    127     int i;
    128     int j;
    129     for (NSString *a in A) {
    130       i = 1;
    131       j++;
    132     }
    133     clang_analyzer_eval(i == 1); // expected-warning {{TRUE}}
    134   }
    135   return 0;
    136 }
    137 
    138 void onlySuppressExitAfterZeroIterations(NSMutableDictionary *D) {
    139   if (D.count > 0) {
    140     int *x;
    141     int i;
    142     for (NSString *key in D) {
    143       x = 0;
    144       i++;
    145     }
    146     // Test that this is reachable.
    147     int y = *x; // expected-warning {{Dereference of null pointer}}
    148     y++;
    149   }
    150 }
    151 
    152 void onlySuppressLoopExitAfterZeroIterations_WithContinue(NSMutableDictionary *D) {
    153   if (D.count > 0) {
    154     int *x;
    155     int i;
    156     for (NSString *key in D) {
    157       x = 0;
    158       i++;
    159       continue;
    160     }
    161     // Test that this is reachable.
    162     int y = *x; // expected-warning {{Dereference of null pointer}}
    163     y++;
    164   }
    165 }
    166 
    167 int* getPtr();
    168 void onlySuppressLoopExitAfterZeroIterations_WithBreak(NSMutableDictionary *D) {
    169   if (D.count > 0) {
    170     int *x;
    171     int i;
    172     for (NSString *key in D) {
    173       x = 0;
    174       break;
    175       x = getPtr();
    176       i++;
    177     }
    178     int y = *x; // expected-warning {{Dereference of null pointer}}
    179     y++;
    180   }
    181 }
    182 
    183 int consistencyBetweenLoopsWhenCountIsUnconstrained(NSMutableDictionary *D,
    184                                                     int shouldUseCount) {
    185   // Test with or without an initial count.
    186   int count;
    187   if (shouldUseCount)
    188     count = [D count];
    189 
    190   int i;
    191   int j = 0;
    192   for (NSString *key in D) {
    193     i = 5;
    194     j++;
    195   }
    196   for (NSString *key in D)  {
    197     return i; // no-warning
    198   }
    199   return 0;
    200 }
    201 
    202 int consistencyBetweenLoopsWhenCountIsUnconstrained_dual(NSMutableDictionary *D,
    203                                                          int shouldUseCount) {
    204   int count;
    205   if (shouldUseCount)
    206     count = [D count];
    207 
    208   int i = 8;
    209   int j = 1;
    210   for (NSString *key in D) {
    211     i = 0;
    212     j++;
    213   }
    214   for (NSString *key in D)  {
    215     i = 5;
    216     j++;
    217   }
    218   return 5/i;
    219 }
    220 
    221 int consistencyCountThenLoop(NSArray *array) {
    222   if ([array count] == 0)
    223     return 0;
    224 
    225   int x;
    226   for (id y in array)
    227     x = 0;
    228   return x; // no-warning
    229 }
    230 
    231 int consistencyLoopThenCount(NSArray *array) {
    232   int x;
    233   for (id y in array)
    234     x = 0;
    235 
    236   if ([array count] == 0)
    237     return 0;
    238 
    239   return x; // no-warning
    240 }
    241 
    242 void nonMutatingMethodsDoNotInvalidateCountDictionary(NSMutableDictionary *dict,
    243                                                       NSMutableArray *other) {
    244   if ([dict count])
    245     return;
    246 
    247   for (id key in dict)
    248     clang_analyzer_eval(0); // no-warning
    249 
    250   (void)[dict objectForKey:@""];
    251 
    252   for (id key in dict)
    253     clang_analyzer_eval(0); // no-warning
    254 
    255   [dict categoryMethodOnNSDictionary];
    256 
    257   for (id key in dict)
    258     clang_analyzer_eval(0); // no-warning
    259 
    260   [dict setObject:@"" forKey:@""];
    261 
    262   for (id key in dict)
    263     clang_analyzer_eval(0); // expected-warning{{FALSE}}
    264 
    265   // Reset.
    266   if ([dict count])
    267     return;
    268 
    269   for (id key in dict)
    270     clang_analyzer_eval(0); // no-warning
    271 
    272   [other addObject:dict];
    273 
    274   for (id key in dict)
    275     clang_analyzer_eval(0); // expected-warning{{FALSE}}
    276 }
    277 
    278 void nonMutatingMethodsDoNotInvalidateCountArray(NSMutableArray *array,
    279                                                  NSMutableArray *other) {
    280   if ([array count])
    281     return;
    282 
    283   for (id key in array)
    284     clang_analyzer_eval(0); // no-warning
    285 
    286   (void)[array objectEnumerator];
    287 
    288   for (id key in array)
    289     clang_analyzer_eval(0); // no-warning
    290 
    291   [array addObject:@""];
    292 
    293   for (id key in array)
    294     clang_analyzer_eval(0); // expected-warning{{FALSE}}
    295 
    296   // Reset.
    297   if ([array count])
    298     return;
    299 
    300   for (id key in array)
    301     clang_analyzer_eval(0); // no-warning
    302 
    303   [other addObject:array];
    304 
    305   for (id key in array)
    306     clang_analyzer_eval(0); // expected-warning{{FALSE}}
    307 }
    308 
    309 void protocolMethods(NSMutableArray *array) {
    310   if ([array count])
    311     return;
    312 
    313   for (id key in array)
    314     clang_analyzer_eval(0); // no-warning
    315 
    316   NSArray *immutableArray = array;
    317   [immutableArray protocolMethod];
    318 
    319   for (id key in array)
    320     clang_analyzer_eval(0); // no-warning
    321 
    322   [array protocolMethod];
    323 
    324   for (id key in array)
    325     clang_analyzer_eval(0); // expected-warning{{FALSE}}
    326 }
    327