reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    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
  146
  147
// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -analyzer-store=region -verify -fblocks %s
// expected-no-diagnostics

// 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;
- (id)init;
@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 occurred 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-options eagerly-assume=true 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-config eagerly-assume=true and
//  -analyzer-store=region.  The 'eagerly-assume=true' 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
}