354 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Objective-C
		
	
	
	
			
		
		
	
	
			354 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Objective-C
		
	
	
	
// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.Loops,debug.ExprInspection -verify -analyzer-config eagerly-assume=false %s
 | 
						|
 | 
						|
void clang_analyzer_eval(int);
 | 
						|
void clang_analyzer_warnIfReached();
 | 
						|
 | 
						|
#define nil ((id)0)
 | 
						|
 | 
						|
typedef unsigned long NSUInteger;
 | 
						|
@protocol NSFastEnumeration
 | 
						|
- (int)countByEnumeratingWithState:(void *)state objects:(id *)objects count:(unsigned)count;
 | 
						|
- (void)protocolMethod;
 | 
						|
@end
 | 
						|
 | 
						|
@interface NSObject
 | 
						|
+ (instancetype)testObject;
 | 
						|
@end
 | 
						|
 | 
						|
@interface NSEnumerator <NSFastEnumeration>
 | 
						|
@end
 | 
						|
 | 
						|
@interface NSArray : NSObject <NSFastEnumeration>
 | 
						|
- (NSUInteger)count;
 | 
						|
- (NSEnumerator *)objectEnumerator;
 | 
						|
+ (NSArray *)arrayWithObjects:(const id [])objects count:(NSUInteger)count;
 | 
						|
@end
 | 
						|
 | 
						|
@interface NSDictionary : NSObject <NSFastEnumeration>
 | 
						|
- (NSUInteger)count;
 | 
						|
- (id)objectForKey:(id)key;
 | 
						|
+ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id /* <NSCopying> */ [])keys count:(NSUInteger)count;
 | 
						|
@end
 | 
						|
 | 
						|
@interface NSDictionary (SomeCategory)
 | 
						|
- (void)categoryMethodOnNSDictionary;
 | 
						|
- (id) allKeys;
 | 
						|
@end
 | 
						|
 | 
						|
@interface NSMutableDictionary : NSDictionary
 | 
						|
- (void)setObject:(id)obj forKey:(id)key;
 | 
						|
@end
 | 
						|
 | 
						|
@interface NSMutableArray : NSArray
 | 
						|
- (void)addObject:(id)obj;
 | 
						|
@end
 | 
						|
 | 
						|
@interface NSSet : NSObject <NSFastEnumeration>
 | 
						|
- (NSUInteger)count;
 | 
						|
@end
 | 
						|
 | 
						|
@interface NSPointerArray : NSObject <NSFastEnumeration>
 | 
						|
@end
 | 
						|
 | 
						|
@interface NSString : NSObject
 | 
						|
@end
 | 
						|
 | 
						|
void test() {
 | 
						|
  id x;
 | 
						|
  for (x in [NSArray testObject])
 | 
						|
    clang_analyzer_eval(x != nil); // expected-warning{{TRUE}}
 | 
						|
 | 
						|
  for (x in [NSMutableDictionary testObject])
 | 
						|
    clang_analyzer_eval(x != nil); // expected-warning{{TRUE}}
 | 
						|
 | 
						|
  for (x in [NSSet testObject])
 | 
						|
    clang_analyzer_eval(x != nil); // expected-warning{{TRUE}}
 | 
						|
 | 
						|
  for (x in [[NSArray testObject] objectEnumerator])
 | 
						|
    clang_analyzer_eval(x != nil); // expected-warning{{TRUE}}
 | 
						|
 | 
						|
  for (x in [NSPointerArray testObject])
 | 
						|
    clang_analyzer_eval(x != nil); // expected-warning{{UNKNOWN}}
 | 
						|
}
 | 
						|
 | 
						|
void testWithVarInFor() {
 | 
						|
  for (id x in [NSArray testObject])
 | 
						|
    clang_analyzer_eval(x != nil); // expected-warning{{TRUE}}
 | 
						|
  for (id x in [NSPointerArray testObject])
 | 
						|
    clang_analyzer_eval(x != nil); // expected-warning{{UNKNOWN}}
 | 
						|
}
 | 
						|
 | 
						|
void testNonNil(id a, id b) {
 | 
						|
  clang_analyzer_eval(a != nil); // expected-warning{{UNKNOWN}}
 | 
						|
  for (id x in a)
 | 
						|
    clang_analyzer_eval(a != nil); // expected-warning{{TRUE}}
 | 
						|
 | 
						|
  if (b != nil)
 | 
						|
    return;
 | 
						|
  for (id x in b)
 | 
						|
    *(volatile int *)0 = 1; // no-warning
 | 
						|
  clang_analyzer_eval(b != nil); // expected-warning{{FALSE}}
 | 
						|
}
 | 
						|
 | 
						|
void collectionIsEmpty(NSMutableDictionary *D){
 | 
						|
  if ([D count] == 0) { // Count is zero.
 | 
						|
    NSString *s = 0;
 | 
						|
    for (NSString *key in D) {
 | 
						|
      s = key;       // Loop is never entered.
 | 
						|
    }
 | 
						|
    clang_analyzer_eval(s == 0); //expected-warning{{TRUE}}
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void processCollection(NSMutableDictionary *D);
 | 
						|
void collectionIsEmptyCollectionIsModified(NSMutableDictionary *D){
 | 
						|
  if ([D count] == 0) {      // Count is zero.
 | 
						|
    NSString *s = 0;
 | 
						|
    processCollection(D);  // However, the collection has changed.
 | 
						|
    for (NSString *key in D) {
 | 
						|
      s = key;       // Loop might be entered.
 | 
						|
    }
 | 
						|
    clang_analyzer_eval(s == 0); //expected-warning{{FALSE}} //expected-warning{{TRUE}}
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
int collectionIsEmptyNSSet(NSSet *S){
 | 
						|
  if ([S count] == 2) { // Count is non-zero.
 | 
						|
    int tapCounts[2];
 | 
						|
    int i = 0;
 | 
						|
    for (NSString *elem in S) {
 | 
						|
      tapCounts[i]= 1;       // Loop is entered.
 | 
						|
      i++;
 | 
						|
    }
 | 
						|
    return (tapCounts[0]); //no warning
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
int collectionIsNotEmptyNSArray(NSArray *A) {
 | 
						|
  int count = [A count];
 | 
						|
  if (count > 0) {
 | 
						|
    int i;
 | 
						|
    int j = 0;
 | 
						|
    for (NSString *a in A) {
 | 
						|
      i = 1;
 | 
						|
      j++;
 | 
						|
    }
 | 
						|
    clang_analyzer_eval(i == 1); // expected-warning {{TRUE}}
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
void onlySuppressExitAfterZeroIterations(NSMutableDictionary *D) {
 | 
						|
  if (D.count > 0) {
 | 
						|
    int *x;
 | 
						|
    int i = 0;
 | 
						|
    for (NSString *key in D) {
 | 
						|
      x = 0;
 | 
						|
      i++;
 | 
						|
    }
 | 
						|
    // Test that this is reachable.
 | 
						|
    int y = *x; // expected-warning {{Dereference of null pointer}}
 | 
						|
    y++;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void onlySuppressLoopExitAfterZeroIterations_WithContinue(NSMutableDictionary *D) {
 | 
						|
  if (D.count > 0) {
 | 
						|
    int *x;
 | 
						|
    int i = 0;
 | 
						|
    for (NSString *key in D) {
 | 
						|
      x = 0;
 | 
						|
      i++;
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
    // Test that this is reachable.
 | 
						|
    int y = *x; // expected-warning {{Dereference of null pointer}}
 | 
						|
    y++;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
int* getPtr();
 | 
						|
void onlySuppressLoopExitAfterZeroIterations_WithBreak(NSMutableDictionary *D) {
 | 
						|
  if (D.count > 0) {
 | 
						|
    int *x;
 | 
						|
    int i;
 | 
						|
    for (NSString *key in D) {
 | 
						|
      x = 0;
 | 
						|
      break;
 | 
						|
      x = getPtr();
 | 
						|
      i++;
 | 
						|
    }
 | 
						|
    int y = *x; // expected-warning {{Dereference of null pointer}}
 | 
						|
    y++;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
int consistencyBetweenLoopsWhenCountIsUnconstrained(NSMutableDictionary *D,
 | 
						|
                                                    int shouldUseCount) {
 | 
						|
  // Test with or without an initial count.
 | 
						|
  int count;
 | 
						|
  if (shouldUseCount)
 | 
						|
    count = [D count];
 | 
						|
 | 
						|
  int i;
 | 
						|
  int j = 0;
 | 
						|
  for (NSString *key in D) {
 | 
						|
    i = 5;
 | 
						|
    j++;
 | 
						|
  }
 | 
						|
  for (NSString *key in D)  {
 | 
						|
    return i; // no-warning
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
int consistencyBetweenLoopsWhenCountIsUnconstrained_dual(NSMutableDictionary *D,
 | 
						|
                                                         int shouldUseCount) {
 | 
						|
  int count;
 | 
						|
  if (shouldUseCount)
 | 
						|
    count = [D count];
 | 
						|
 | 
						|
  int i = 8;
 | 
						|
  int j = 1;
 | 
						|
  for (NSString *key in D) {
 | 
						|
    i = 0;
 | 
						|
    j++;
 | 
						|
  }
 | 
						|
  for (NSString *key in D)  {
 | 
						|
    i = 5;
 | 
						|
    j++;
 | 
						|
  }
 | 
						|
  return 5/i;
 | 
						|
}
 | 
						|
 | 
						|
int consistencyCountThenLoop(NSArray *array) {
 | 
						|
  if ([array count] == 0)
 | 
						|
    return 0;
 | 
						|
 | 
						|
  int x;
 | 
						|
  for (id y in array)
 | 
						|
    x = 0;
 | 
						|
  return x; // no-warning
 | 
						|
}
 | 
						|
 | 
						|
int consistencyLoopThenCount(NSArray *array) {
 | 
						|
  int x;
 | 
						|
  for (id y in array)
 | 
						|
    x = 0;
 | 
						|
 | 
						|
  if ([array count] == 0)
 | 
						|
    return 0;
 | 
						|
 | 
						|
  return x; // no-warning
 | 
						|
}
 | 
						|
 | 
						|
void nonMutatingMethodsDoNotInvalidateCountDictionary(NSMutableDictionary *dict,
 | 
						|
                                                      NSMutableArray *other) {
 | 
						|
  if ([dict count])
 | 
						|
    return;
 | 
						|
 | 
						|
  for (id key in dict)
 | 
						|
    clang_analyzer_eval(0); // no-warning
 | 
						|
 | 
						|
  (void)[dict objectForKey:@""];
 | 
						|
 | 
						|
  for (id key in dict)
 | 
						|
    clang_analyzer_eval(0); // no-warning
 | 
						|
 | 
						|
  [dict categoryMethodOnNSDictionary];
 | 
						|
 | 
						|
  for (id key in dict)
 | 
						|
    clang_analyzer_eval(0); // no-warning
 | 
						|
 | 
						|
  [dict setObject:@"" forKey:@""];
 | 
						|
 | 
						|
  for (id key in dict)
 | 
						|
    clang_analyzer_eval(0); // expected-warning{{FALSE}}
 | 
						|
 | 
						|
  // Reset.
 | 
						|
  if ([dict count])
 | 
						|
    return;
 | 
						|
 | 
						|
  for (id key in dict)
 | 
						|
    clang_analyzer_eval(0); // no-warning
 | 
						|
 | 
						|
  [other addObject:dict];
 | 
						|
 | 
						|
  for (id key in dict)
 | 
						|
    clang_analyzer_eval(0); // expected-warning{{FALSE}}
 | 
						|
}
 | 
						|
 | 
						|
void nonMutatingMethodsDoNotInvalidateCountArray(NSMutableArray *array,
 | 
						|
                                                 NSMutableArray *other) {
 | 
						|
  if ([array count])
 | 
						|
    return;
 | 
						|
 | 
						|
  for (id key in array)
 | 
						|
    clang_analyzer_eval(0); // no-warning
 | 
						|
 | 
						|
  (void)[array objectEnumerator];
 | 
						|
 | 
						|
  for (id key in array)
 | 
						|
    clang_analyzer_eval(0); // no-warning
 | 
						|
 | 
						|
  [array addObject:@""];
 | 
						|
 | 
						|
  for (id key in array)
 | 
						|
    clang_analyzer_eval(0); // expected-warning{{FALSE}}
 | 
						|
 | 
						|
  // Reset.
 | 
						|
  if ([array count])
 | 
						|
    return;
 | 
						|
 | 
						|
  for (id key in array)
 | 
						|
    clang_analyzer_eval(0); // no-warning
 | 
						|
 | 
						|
  [other addObject:array];
 | 
						|
 | 
						|
  for (id key in array)
 | 
						|
    clang_analyzer_eval(0); // expected-warning{{FALSE}}
 | 
						|
}
 | 
						|
 | 
						|
void protocolMethods(NSMutableArray *array) {
 | 
						|
  if ([array count])
 | 
						|
    return;
 | 
						|
 | 
						|
  for (id key in array)
 | 
						|
    clang_analyzer_eval(0); // no-warning
 | 
						|
 | 
						|
  NSArray *immutableArray = array;
 | 
						|
  [immutableArray protocolMethod];
 | 
						|
 | 
						|
  for (id key in array)
 | 
						|
    clang_analyzer_eval(0); // no-warning
 | 
						|
 | 
						|
  [array protocolMethod];
 | 
						|
 | 
						|
  for (id key in array)
 | 
						|
    clang_analyzer_eval(0); // expected-warning{{FALSE}}
 | 
						|
}
 | 
						|
 | 
						|
NSArray *globalArray;
 | 
						|
NSDictionary *globalDictionary;
 | 
						|
void boxedArrayEscape(NSMutableArray *array) {
 | 
						|
  if ([array count])
 | 
						|
    return;
 | 
						|
  globalArray = @[array];
 | 
						|
  for (id key in array)
 | 
						|
    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
 | 
						|
 | 
						|
  if ([array count])
 | 
						|
    return;
 | 
						|
  globalDictionary = @{ @"array" : array };
 | 
						|
  for (id key in array)
 | 
						|
    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
 | 
						|
}
 | 
						|
 | 
						|
int not_reachable_on_iteration_through_nil() {
 | 
						|
  NSDictionary* d = nil;
 | 
						|
  for (NSString* s in [d allKeys])
 | 
						|
    clang_analyzer_warnIfReached(); // no-warning
 | 
						|
  return 0;
 | 
						|
}
 |