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