Home | History | Annotate | Download | only in Analysis
      1 // RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -analyzer-constraints=range -verify -fblocks %s -analyzer-eagerly-assume
      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-eagerly-assume 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-eagerly-assume and
    129 //  -analyzer-store=region.  The '-analyzer-eagerly-assume' 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