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