1// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core -fblocks -verify -Wno-strict-prototypes %s 2// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core -fblocks -verify -x objective-c++ %s 3 4//===----------------------------------------------------------------------===// 5// The following code is reduced using delta-debugging from Mac OS X headers: 6//===----------------------------------------------------------------------===// 7 8typedef __builtin_va_list va_list; 9typedef unsigned int uint32_t; 10typedef struct dispatch_queue_s *dispatch_queue_t; 11typedef struct dispatch_queue_attr_s *dispatch_queue_attr_t; 12typedef void (^dispatch_block_t)(void); 13void dispatch_async(dispatch_queue_t queue, dispatch_block_t block); 14__attribute__((visibility("default"))) __attribute__((__malloc__)) __attribute__((__warn_unused_result__)) __attribute__((__nothrow__)) dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr); 15typedef long dispatch_once_t; 16void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block); 17dispatch_queue_t 18dispatch_queue_create(const char *label, dispatch_queue_attr_t attr); 19 20 21typedef signed char BOOL; 22typedef unsigned long NSUInteger; 23typedef struct _NSZone NSZone; 24@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; 25@protocol NSObject 26- (BOOL)isEqual:(id)object; 27- (oneway void)release; 28@end 29@protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end 30@protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; @end 31@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end 32@interface NSObject <NSObject> {} 33+ (id)alloc; 34- (id)init; 35- (id)copy; 36@end 37extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone); 38@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding> 39- (NSUInteger)length; 40- (const char *)UTF8String; 41- (id)initWithFormat:(NSString *)format arguments:(va_list)argList __attribute__((format(__NSString__, 1, 0))); 42@end 43@class NSString, NSData; 44typedef struct cssm_sample {} CSSM_SAMPLEGROUP, *CSSM_SAMPLEGROUP_PTR; 45typedef struct __aslclient *aslclient; 46typedef struct __aslmsg *aslmsg; 47aslclient asl_open(const char *ident, const char *facility, uint32_t opts); 48int asl_log(aslclient asl, aslmsg msg, int level, const char *format, ...) __attribute__((__format__ (__printf__, 4, 5))); 49 50struct Block_layout { 51 int flags; 52}; 53 54//===----------------------------------------------------------------------===// 55// Begin actual test cases. 56//===----------------------------------------------------------------------===// 57 58// test1 - This test case exposed logic that caused the analyzer to crash because of a memory bug 59// in BlockDataRegion. It represents real code that contains two block literals. Eventually 60// via IPA 'logQueue' and 'client' should be updated after the call to 'dispatch_once'. 61void test1(NSString *format, ...) { 62 static dispatch_queue_t logQueue; 63 static aslclient client; 64 static dispatch_once_t pred; 65 do { 66 if (__builtin_expect(*(&pred), ~0l) != ~0l) 67 dispatch_once(&pred, ^{ 68 logQueue = dispatch_queue_create("com.mycompany.myproduct.asl", 0); 69 client = asl_open(((char*)0), "com.mycompany.myproduct", 0); 70 }); 71 } while (0); 72 73 va_list args; 74 __builtin_va_start(args, format); 75 76 NSString *str = [[NSString alloc] initWithFormat:format arguments:args]; 77 dispatch_async(logQueue, ^{ asl_log(client, ((aslmsg)0), 4, "%s", [str UTF8String]); }); 78 [str release]; 79 80 __builtin_va_end(args); 81} 82 83// test2 - Test that captured variables that are uninitialized are flagged 84// as such. 85void test2(void) { 86 static int y = 0; 87 int x; 88 ^{ y = x + 1; }(); // expected-warning{{Variable 'x' is uninitialized when captured by block}} 89} 90 91void test2_b(void) { 92 static int y = 0; 93 __block int x; 94 ^{ y = x + 1; }(); // expected-warning {{left operand of '+' is a garbage value}} 95} 96 97void test2_c(void) { 98 typedef void (^myblock)(void); 99 myblock f = ^(void) { f(); }; // expected-warning{{Variable 'f' is uninitialized when captured by block}} 100} 101 102 103void testMessaging(void) { 104 // <rdar://problem/12119814> 105 [[^(void){} copy] release]; 106} 107 108 109@interface rdar12415065 : NSObject 110@end 111 112@implementation rdar12415065 113- (void)test { 114 // At one point this crashed because we created a path note at a 115 // PreStmtPurgeDeadSymbols point but only knew how to deal with PostStmt 116 // points. <rdar://problem/12687586> 117 118 extern dispatch_queue_t queue; 119 120 if (!queue) 121 return; 122 123 // This previously was a false positive with 'x' being flagged as being 124 // uninitialized when captured by the exterior block (when it is only 125 // captured by the interior block). 126 dispatch_async(queue, ^{ 127 double x = 0.0; 128 if (24.0f < x) { 129 dispatch_async(queue, ^{ (void)x; }); 130 [self test]; 131 } 132 }); 133} 134@end 135 136void testReturnVariousSignatures(void) { 137 (void)^int(void){ 138 return 42; 139 }(); 140 141 (void)^int{ 142 return 42; 143 }(); 144 145 (void)^(void){ 146 return 42; 147 }(); 148 149 (void)^{ 150 return 42; 151 }(); 152} 153 154// This test used to cause infinite loop in the region invalidation. 155void blockCapturesItselfInTheLoop(int x, int m) { 156 void (^assignData)(int) = ^(int x){ 157 x++; 158 }; 159 while (m < 0) { 160 void (^loop)(int); 161 loop = ^(int x) { 162 assignData(x); 163 }; 164 assignData = loop; 165 m++; 166 } 167 assignData(x); 168} 169 170// Blocks that called the function they were contained in that also have 171// static locals caused crashes. 172// rdar://problem/21698099 173void takeNonnullBlock(void (^)(void)) __attribute__((nonnull)); 174void takeNonnullIntBlock(int (^)(void)) __attribute__((nonnull)); 175 176void testCallContainingWithSignature1(void) 177{ 178 takeNonnullBlock(^{ 179 static const char str[] = "Lost connection to sharingd"; 180 testCallContainingWithSignature1(); 181 }); 182} 183 184void testCallContainingWithSignature2(void) 185{ 186 takeNonnullBlock(^void{ 187 static const char str[] = "Lost connection to sharingd"; 188 testCallContainingWithSignature2(); 189 }); 190} 191 192void testCallContainingWithSignature3(void) 193{ 194 takeNonnullBlock(^void(void){ 195 static const char str[] = "Lost connection to sharingd"; 196 testCallContainingWithSignature3(); 197 }); 198} 199 200void testCallContainingWithSignature4(void) 201{ 202 takeNonnullBlock(^void(void){ 203 static const char str[] = "Lost connection to sharingd"; 204 testCallContainingWithSignature4(); 205 }); 206} 207 208void testCallContainingWithSignature5(void) 209{ 210 takeNonnullIntBlock(^{ 211 static const char str[] = "Lost connection to sharingd"; 212 testCallContainingWithSignature5(); 213 return 0; 214 }); 215} 216 217__attribute__((objc_root_class)) 218@interface SuperClass 219- (void)someMethod; 220@end 221 222@interface SomeClass : SuperClass 223@end 224 225// Make sure to properly handle super-calls when a block captures 226// a local variable named 'self'. 227@implementation SomeClass 228-(void)foo; { 229 /*__weak*/ SomeClass *weakSelf = self; 230 (void)(^(void) { 231 SomeClass *self = weakSelf; 232 (void)(^(void) { 233 (void)self; 234 [super someMethod]; // no-warning 235 }); 236 }); 237} 238@end 239 240// The incorrect block variable initialization below is a hard compile-time 241// error in C++. 242#if !defined(__cplusplus) 243void call_block_with_fewer_arguments(void) { 244 void (^b)() = ^(int a) { }; 245 b(); // expected-warning {{Block taking 1 argument is called with fewer (0)}} 246} 247#endif 248 249int getBlockFlags(void) { 250 int x = 0; 251 return ((struct Block_layout *)^{ (void)x; })->flags; // no-warning 252} 253