aboutsummaryrefslogtreecommitdiff
path: root/test/Analysis/misc-ps-eager-assume.m
blob: c23efab416e9b34c60c08ffcafba0afb74cf49c6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// RUN: %clang_cc1 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s -analyzer-eagerly-assume

// Delta-reduced header stuff (needed for test cases).
typedef signed char BOOL;
typedef unsigned int NSUInteger;
typedef struct _NSZone NSZone;
@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
@protocol NSObject  - (BOOL)isEqual:(id)object;
- (oneway void)release;
@end  @protocol NSCopying  - (id)copyWithZone:(NSZone *)zone;
@end  @protocol NSMutableCopying  - (id)mutableCopyWithZone:(NSZone *)zone;
@end  @protocol NSCoding  - (void)encodeWithCoder:(NSCoder *)aCoder;
@end    @interface NSObject <NSObject> {}
+ (id)alloc;
@end  typedef struct {}
NSFastEnumerationState;
@protocol NSFastEnumeration  - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len;
@end      @interface NSArray : NSObject <NSCopying, NSMutableCopying, NSCoding, NSFastEnumeration>  - (NSUInteger)count;
@end    @interface NSMutableArray : NSArray  - (void)addObject:(id)anObject;
- (BOOL)isEqualToString:(NSString *)aString;
@end        @interface NSAutoreleasePool : NSObject {}
- (void)drain;
- (id)init;
@end

// This test case tests that (x != 0) is eagerly evaluated before stored to
// 'y'.  This test case complements recoverCastedSymbol (see below) because
// the symbolic expression is stored to 'y' (which is a short instead of an
// int).  recoverCastedSymbol() only recovers path-sensitivity when the
// symbolic expression is literally the branch condition.
//
void handle_assign_of_condition(int x) {
  // The cast to 'short' causes us to lose symbolic constraint.
  short y = (x != 0);
  char *p = 0;
  if (y) {
    // This should be infeasible.
    if (!(x != 0)) {
      *p = 1;  // no-warning
    }
  }
}

// From <rdar://problem/6619921>
//
// In this test case, 'needsAnArray' is a signed char.  The analyzer tracks
// a symbolic value for this variable, but in the branch condition it is
// promoted to 'int'.  Currently the analyzer doesn't reason well about
// promotions of symbolic values, so this test case tests the logic in
// 'recoverCastedSymbol()' (GRExprEngine.cpp) to test that we recover
// path-sensitivity and use the symbol for 'needsAnArray' in the branch
// condition.
//
void handle_symbolic_cast_in_condition(void) {
  NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];

  BOOL needsAnArray = [@"aString" isEqualToString:@"anotherString"];
  NSMutableArray* array = needsAnArray ? [[NSMutableArray alloc] init] : 0;
  if(needsAnArray)
    [array release];

  [pool drain];
}

// From PR 3836 (http://llvm.org/bugs/show_bug.cgi?id=3836)
//
// In this test case, the double '!' works fine with our symbolic constraints,
// but we don't support comparing SymConstraint != SymConstraint.  By eagerly
// assuming the truth of !!a or !!b, we can compare these values directly.
//
void pr3836(int *a, int *b) {
  if (!!a != !!b) /* one of them is NULL */
    return;
  if (!a && !b) /* both are NULL */
    return;
      
  *a = 1; // no-warning
  *b = 1; // no-warning
}


//===---------------------------------------------------------------------===//
// <rdar://problem/7342806>
// This false positive occured because the symbolic constraint on a short was
// not maintained via sign extension.  The analyzer doesn't properly handle
// the sign extension, but now tracks the constraint.  This particular
// case relies on -analyzer-eagerly-assume because of the expression
// 'Flag1 != Count > 0'.
//===---------------------------------------------------------------------===//

void rdar7342806_aux(short x);

void rdar7342806() {
  extern short Count;
  extern short Flag1;

  short *Pointer = 0;
  short  Flag2   = !!Pointer;   // Flag2 is false (0).
  short  Ok      = 1;
  short  Which;

  if( Flag1 != Count > 0 )
    // Static analyzer skips this so either
    //   Flag1 is true and Count > 0
    // or
    //   Flag1 is false and Count <= 0
    Ok = 0;

  if( Flag1 != Flag2 )
    // Analyzer skips this so Flag1 and Flag2 have the
    // same value, both are false because Flag2 is false. And
    // from that we know Count must be <= 0.
    Ok = 0;

  for( Which = 0;
         Which < Count && Ok;
           Which++ )
    // This statement can only execute if Count > 0 which can only
    // happen when Flag1 and Flag2 are both true and Flag2 will only
    // be true when Pointer is not NULL.
    rdar7342806_aux(*Pointer); // no-warning
}

//===---------------------------------------------------------------------===//
// PR 5627 - http://llvm.org/bugs/show_bug.cgi?id=5627
//  This test case depends on using -analyzer-eagerly-assume and
//  -analyzer-store=region.  The '-analyzer-eagerly-assume' causes the path
//  to bifurcate when evaluating the function call argument, and a state
//  caching bug in GRExprEngine::CheckerVisit (and friends) caused the store
//  to 'p' to not be evaluated along one path, but then an autotransition caused
//  the path to keep on propagating with 'p' still set to an undefined value.
//  We would then get a bogus report of returning uninitialized memory.
//  Note: CheckerVisit mistakenly cleared an existing node, and the cleared
//  node was resurrected by GRStmtNodeBuilder::~GRStmtNodeBuilder(), where
//  'p' was not assigned.
//===---------------------------------------------------------------------===//

float *pr5627_f(int y);

float *pr5627_g(int x) {
  float *p;
  p = pr5627_f(!x);
  return p; // no-warning
}