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