Ted Kremenek | 8382cf5 | 2009-11-13 18:46:29 +0000 | [diff] [blame] | 1 | // RUN: clang-cc -analyze -analyzer-experimental-internal-checks -checker-cfref --analyzer-store=region -analyzer-constraints=range --verify -fblocks %s -analyzer-eagerly-assume |
Ted Kremenek | 48af2a9 | 2009-02-25 22:32:02 +0000 | [diff] [blame] | 2 | |
Ted Kremenek | 6ae8a36 | 2009-03-13 16:32:54 +0000 | [diff] [blame] | 3 | // Delta-reduced header stuff (needed for test cases). |
| 4 | typedef signed char BOOL; |
| 5 | typedef unsigned int NSUInteger; |
| 6 | typedef 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 | @end typedef struct {} |
| 16 | NSFastEnumerationState; |
| 17 | @protocol NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len; |
| 18 | @end @interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration> - (NSUInteger)count; |
| 19 | @end @interface NSMutableArray : NSArray - (void)addObject:(id)anObject; |
| 20 | - (BOOL)isEqualToString:(NSString *)aString; |
| 21 | @end @interface NSAutoreleasePool : NSObject {} |
| 22 | - (void)drain; |
| 23 | - (id)init; |
| 24 | @end |
| 25 | |
| 26 | // This test case tests that (x != 0) is eagerly evaluated before stored to |
| 27 | // 'y'. This test case complements recoverCastedSymbol (see below) because |
| 28 | // the symbolic expression is stored to 'y' (which is a short instead of an |
| 29 | // int). recoverCastedSymbol() only recovers path-sensitivity when the |
| 30 | // symbolic expression is literally the branch condition. |
| 31 | // |
Ted Kremenek | 48af2a9 | 2009-02-25 22:32:02 +0000 | [diff] [blame] | 32 | void handle_assign_of_condition(int x) { |
| 33 | // The cast to 'short' causes us to lose symbolic constraint. |
| 34 | short y = (x != 0); |
| 35 | char *p = 0; |
| 36 | if (y) { |
| 37 | // This should be infeasible. |
| 38 | if (!(x != 0)) { |
| 39 | *p = 1; // no-warning |
| 40 | } |
| 41 | } |
| 42 | } |
| 43 | |
Ted Kremenek | 6ae8a36 | 2009-03-13 16:32:54 +0000 | [diff] [blame] | 44 | // From <rdar://problem/6619921> |
| 45 | // |
| 46 | // In this test case, 'needsAnArray' is a signed char. The analyzer tracks |
| 47 | // a symbolic value for this variable, but in the branch condition it is |
| 48 | // promoted to 'int'. Currently the analyzer doesn't reason well about |
| 49 | // promotions of symbolic values, so this test case tests the logic in |
| 50 | // 'recoverCastedSymbol()' (GRExprEngine.cpp) to test that we recover |
| 51 | // path-sensitivity and use the symbol for 'needsAnArray' in the branch |
| 52 | // condition. |
| 53 | // |
| 54 | void handle_symbolic_cast_in_condition(void) { |
| 55 | NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
| 56 | |
| 57 | BOOL needsAnArray = [@"aString" isEqualToString:@"anotherString"]; |
| 58 | NSMutableArray* array = needsAnArray ? [[NSMutableArray alloc] init] : 0; |
| 59 | if(needsAnArray) |
| 60 | [array release]; |
| 61 | |
| 62 | [pool drain]; |
| 63 | } |
Ted Kremenek | 7237459 | 2009-03-18 23:49:26 +0000 | [diff] [blame] | 64 | |
| 65 | // From PR 3836 (http://llvm.org/bugs/show_bug.cgi?id=3836) |
| 66 | // |
| 67 | // In this test case, the double '!' works fine with our symbolic constraints, |
| 68 | // but we don't support comparing SymConstraint != SymConstraint. By eagerly |
| 69 | // assuming the truth of !!a or !!b, we can compare these values directly. |
| 70 | // |
| 71 | void pr3836(int *a, int *b) { |
| 72 | if (!!a != !!b) /* one of them is NULL */ |
| 73 | return; |
| 74 | if (!a && !b) /* both are NULL */ |
| 75 | return; |
| 76 | |
| 77 | *a = 1; // no-warning |
| 78 | *b = 1; // no-warning |
| 79 | } |
Ted Kremenek | d864e1a | 2009-10-29 00:49:46 +0000 | [diff] [blame] | 80 | |
| 81 | |
| 82 | //===---------------------------------------------------------------------===// |
| 83 | // <rdar://problem/7342806> |
| 84 | // This false positive occured because the symbolic constraint on a short was |
| 85 | // not maintained via sign extension. The analyzer doesn't properly handle |
| 86 | // the sign extension, but now tracks the constraint. This particular |
| 87 | // case relies on -analyzer-eagerly-assume because of the expression |
| 88 | // 'Flag1 != Count > 0'. |
| 89 | //===---------------------------------------------------------------------===// |
| 90 | |
| 91 | void rdar7342806_aux(short x); |
| 92 | |
| 93 | void rdar7342806() { |
| 94 | extern short Count; |
| 95 | extern short Flag1; |
| 96 | |
| 97 | short *Pointer = 0; |
| 98 | short Flag2 = !!Pointer; // Flag2 is false (0). |
| 99 | short Ok = 1; |
| 100 | short Which; |
| 101 | |
| 102 | if( Flag1 != Count > 0 ) |
| 103 | // Static analyzer skips this so either |
| 104 | // Flag1 is true and Count > 0 |
| 105 | // or |
| 106 | // Flag1 is false and Count <= 0 |
| 107 | Ok = 0; |
| 108 | |
| 109 | if( Flag1 != Flag2 ) |
| 110 | // Analyzer skips this so Flag1 and Flag2 have the |
| 111 | // same value, both are false because Flag2 is false. And |
| 112 | // from that we know Count must be <= 0. |
| 113 | Ok = 0; |
| 114 | |
| 115 | for( Which = 0; |
| 116 | Which < Count && Ok; |
| 117 | Which++ ) |
| 118 | // This statement can only execute if Count > 0 which can only |
| 119 | // happen when Flag1 and Flag2 are both true and Flag2 will only |
| 120 | // be true when Pointer is not NULL. |
| 121 | rdar7342806_aux(*Pointer); // no-warning |
| 122 | } |