Home | History | Annotate | Download | only in Analysis
      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).
      4 typedef signed char BOOL;
      5 typedef unsigned int NSUInteger;
      6 typedef 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 {}
     17 NSFastEnumerationState;
     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 //
     33 void 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 //
     55 void 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 //
     72 void 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 
     92 void rdar7342806_aux(short x);
     93 
     94 void 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 
    139 float *pr5627_f(int y);
    140 
    141 float *pr5627_g(int x) {
    142   float *p;
    143   p = pr5627_f(!x);
    144   return p; // no-warning
    145 }
    146 
    147