misc-ps-eager-assume.m revision 033a07e5fca459ed184369cfee7c90d82367a93a
1// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s -analyzer-eagerly-assume 2 3// Delta-reduced header stuff (needed for test cases). 4typedef signed char BOOL; 5typedef unsigned int NSUInteger; 6typedef struct _NSZone NSZone; 7@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; 8@protocol NSObject - (BOOL)isEqual:(id)object; 9- (oneway void)release; 10@end @protocol NSCopying - (id)copyWithZone:(NSZone *)zone; 11@end @protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; 12@end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; 13@end @interface NSObject <NSObject> {} 14+ (id)alloc; 15- (id)init; 16@end typedef struct {} 17NSFastEnumerationState; 18@protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len; 19@end @interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count; 20@end @interface NSMutableArray : NSArray - (void)addObject:(id)anObject; 21- (BOOL)isEqualToString:(NSString *)aString; 22@end @interface NSAutoreleasePool : NSObject {} 23- (void)drain; 24- (id)init; 25@end 26 27// This test case tests that (x != 0) is eagerly evaluated before stored to 28// 'y'. This test case complements recoverCastedSymbol (see below) because 29// the symbolic expression is stored to 'y' (which is a short instead of an 30// int). recoverCastedSymbol() only recovers path-sensitivity when the 31// symbolic expression is literally the branch condition. 32// 33void handle_assign_of_condition(int x) { 34 // The cast to 'short' causes us to lose symbolic constraint. 35 short y = (x != 0); 36 char *p = 0; 37 if (y) { 38 // This should be infeasible. 39 if (!(x != 0)) { 40 *p = 1; // no-warning 41 } 42 } 43} 44 45// From <rdar://problem/6619921> 46// 47// In this test case, 'needsAnArray' is a signed char. The analyzer tracks 48// a symbolic value for this variable, but in the branch condition it is 49// promoted to 'int'. Currently the analyzer doesn't reason well about 50// promotions of symbolic values, so this test case tests the logic in 51// 'recoverCastedSymbol()' (GRExprEngine.cpp) to test that we recover 52// path-sensitivity and use the symbol for 'needsAnArray' in the branch 53// condition. 54// 55void handle_symbolic_cast_in_condition(void) { 56 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 57 58 BOOL needsAnArray = [@"aString" isEqualToString:@"anotherString"]; 59 NSMutableArray* array = needsAnArray ? [[NSMutableArray alloc] init] : 0; 60 if(needsAnArray) 61 [array release]; 62 63 [pool drain]; 64} 65 66// From PR 3836 (http://llvm.org/bugs/show_bug.cgi?id=3836) 67// 68// In this test case, the double '!' works fine with our symbolic constraints, 69// but we don't support comparing SymConstraint != SymConstraint. By eagerly 70// assuming the truth of !!a or !!b, we can compare these values directly. 71// 72void pr3836(int *a, int *b) { 73 if (!!a != !!b) /* one of them is NULL */ 74 return; 75 if (!a && !b) /* both are NULL */ 76 return; 77 78 *a = 1; // no-warning 79 *b = 1; // no-warning 80} 81 82 83//===---------------------------------------------------------------------===// 84// <rdar://problem/7342806> 85// This false positive occurred because the symbolic constraint on a short was 86// not maintained via sign extension. The analyzer doesn't properly handle 87// the sign extension, but now tracks the constraint. This particular 88// case relies on -analyzer-eagerly-assume because of the expression 89// 'Flag1 != Count > 0'. 90//===---------------------------------------------------------------------===// 91 92void rdar7342806_aux(short x); 93 94void rdar7342806() { 95 extern short Count; 96 extern short Flag1; 97 98 short *Pointer = 0; 99 short Flag2 = !!Pointer; // Flag2 is false (0). 100 short Ok = 1; 101 short Which; 102 103 if( Flag1 != Count > 0 ) 104 // Static analyzer skips this so either 105 // Flag1 is true and Count > 0 106 // or 107 // Flag1 is false and Count <= 0 108 Ok = 0; 109 110 if( Flag1 != Flag2 ) 111 // Analyzer skips this so Flag1 and Flag2 have the 112 // same value, both are false because Flag2 is false. And 113 // from that we know Count must be <= 0. 114 Ok = 0; 115 116 for( Which = 0; 117 Which < Count && Ok; 118 Which++ ) 119 // This statement can only execute if Count > 0 which can only 120 // happen when Flag1 and Flag2 are both true and Flag2 will only 121 // be true when Pointer is not NULL. 122 rdar7342806_aux(*Pointer); // no-warning 123} 124 125//===---------------------------------------------------------------------===// 126// PR 5627 - http://llvm.org/bugs/show_bug.cgi?id=5627 127// This test case depends on using -analyzer-eagerly-assume and 128// -analyzer-store=region. The '-analyzer-eagerly-assume' causes the path 129// to bifurcate when evaluating the function call argument, and a state 130// caching bug in GRExprEngine::CheckerVisit (and friends) caused the store 131// to 'p' to not be evaluated along one path, but then an autotransition caused 132// the path to keep on propagating with 'p' still set to an undefined value. 133// We would then get a bogus report of returning uninitialized memory. 134// Note: CheckerVisit mistakenly cleared an existing node, and the cleared 135// node was resurrected by GRStmtNodeBuilder::~GRStmtNodeBuilder(), where 136// 'p' was not assigned. 137//===---------------------------------------------------------------------===// 138 139float *pr5627_f(int y); 140 141float *pr5627_g(int x) { 142 float *p; 143 p = pr5627_f(!x); 144 return p; // no-warning 145} 146 147