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