354 lines
8.0 KiB
Mathematica
354 lines
8.0 KiB
Mathematica
|
// 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;
|
||
|
}
|