blob: a986b8eca62a1d1c6f7bcee2436be156d59143d1 [file] [log] [blame]
Ted Kremenek565e4652010-02-05 02:06:54 +00001// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -analyzer-check-objc-mem -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s -analyzer-eagerly-assume
Ted Kremenek48af2a92009-02-25 22:32:02 +00002
Ted Kremenek6ae8a362009-03-13 16:32:54 +00003// 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@end typedef struct {}
16NSFastEnumerationState;
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 Kremenek48af2a92009-02-25 22:32:02 +000032void 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 Kremenek6ae8a362009-03-13 16:32:54 +000044// 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//
54void 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 Kremenek72374592009-03-18 23:49:26 +000064
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//
71void 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 Kremenekd864e1a2009-10-29 00:49:46 +000080
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
91void rdar7342806_aux(short x);
92
93void 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}
Ted Kremenek17f4da82009-12-09 02:45:41 +0000123
124//===---------------------------------------------------------------------===//
125// PR 5627 - http://llvm.org/bugs/show_bug.cgi?id=5627
126// This test case depends on using -analyzer-eagerly-assume and
127// -analyzer-store=region. The '-analyzer-eagerly-assume' causes the path
128// to bifurcate when evaluating the function call argument, and a state
129// caching bug in GRExprEngine::CheckerVisit (and friends) caused the store
130// to 'p' to not be evaluated along one path, but then an autotransition caused
131// the path to keep on propagating with 'p' still set to an undefined value.
132// We would then get a bogus report of returning uninitialized memory.
Zhongxing Xubcb02fc2009-12-09 04:22:30 +0000133// Note: CheckerVisit mistakenly cleared an existing node, and the cleared
134// node was resurrected by GRStmtNodeBuilder::~GRStmtNodeBuilder(), where
135// 'p' was not assigned.
Ted Kremenek17f4da82009-12-09 02:45:41 +0000136//===---------------------------------------------------------------------===//
137
138float *pr5627_f(int y);
139
140float *pr5627_g(int x) {
141 float *p;
142 p = pr5627_f(!x);
143 return p; // no-warning
144}
145