diff options
Diffstat (limited to 'clang/test/Analysis/misc-ps-eager-assume.m')
| -rw-r--r-- | clang/test/Analysis/misc-ps-eager-assume.m | 146 | 
1 files changed, 146 insertions, 0 deletions
diff --git a/clang/test/Analysis/misc-ps-eager-assume.m b/clang/test/Analysis/misc-ps-eager-assume.m new file mode 100644 index 0000000..0aff8e4 --- /dev/null +++ b/clang/test/Analysis/misc-ps-eager-assume.m @@ -0,0 +1,146 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,experimental.core -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; +- (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-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 +} +  | 
