misc-ps-eager-assume.m revision 4c4efee6d3113f20b41efaeec08934332d2ea40e
1// RUN: %clang_cc1 -analyze -analyzer-checker=core,core.experimental -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