1*3cab2bb3Spatrick// Mac OS X 10.6 or higher only. 2*3cab2bb3Spatrick#include <dispatch/dispatch.h> 3*3cab2bb3Spatrick#include <pthread.h> // for pthread_yield_np() 4*3cab2bb3Spatrick#include <stdio.h> 5*3cab2bb3Spatrick#include <stdlib.h> 6*3cab2bb3Spatrick#include <string.h> 7*3cab2bb3Spatrick#include <unistd.h> 8*3cab2bb3Spatrick 9*3cab2bb3Spatrick#import <CoreFoundation/CFBase.h> 10*3cab2bb3Spatrick#import <Foundation/NSObject.h> 11*3cab2bb3Spatrick#import <Foundation/NSURL.h> 12*3cab2bb3Spatrick 13*3cab2bb3Spatrick// This is a (void*)(void*) function so it can be passed to pthread_create. 14*3cab2bb3Spatrickvoid *CFAllocatorDefaultDoubleFree(void *unused) { 15*3cab2bb3Spatrick void *mem = CFAllocatorAllocate(kCFAllocatorDefault, 5, 0); 16*3cab2bb3Spatrick CFAllocatorDeallocate(kCFAllocatorDefault, mem); 17*3cab2bb3Spatrick CFAllocatorDeallocate(kCFAllocatorDefault, mem); 18*3cab2bb3Spatrick return 0; 19*3cab2bb3Spatrick} 20*3cab2bb3Spatrick 21*3cab2bb3Spatrickvoid CFAllocatorSystemDefaultDoubleFree() { 22*3cab2bb3Spatrick void *mem = CFAllocatorAllocate(kCFAllocatorSystemDefault, 5, 0); 23*3cab2bb3Spatrick CFAllocatorDeallocate(kCFAllocatorSystemDefault, mem); 24*3cab2bb3Spatrick CFAllocatorDeallocate(kCFAllocatorSystemDefault, mem); 25*3cab2bb3Spatrick} 26*3cab2bb3Spatrick 27*3cab2bb3Spatrickvoid CFAllocatorMallocDoubleFree() { 28*3cab2bb3Spatrick void *mem = CFAllocatorAllocate(kCFAllocatorMalloc, 5, 0); 29*3cab2bb3Spatrick CFAllocatorDeallocate(kCFAllocatorMalloc, mem); 30*3cab2bb3Spatrick CFAllocatorDeallocate(kCFAllocatorMalloc, mem); 31*3cab2bb3Spatrick} 32*3cab2bb3Spatrick 33*3cab2bb3Spatrickvoid CFAllocatorMallocZoneDoubleFree() { 34*3cab2bb3Spatrick void *mem = CFAllocatorAllocate(kCFAllocatorMallocZone, 5, 0); 35*3cab2bb3Spatrick CFAllocatorDeallocate(kCFAllocatorMallocZone, mem); 36*3cab2bb3Spatrick CFAllocatorDeallocate(kCFAllocatorMallocZone, mem); 37*3cab2bb3Spatrick} 38*3cab2bb3Spatrick 39*3cab2bb3Spatrick__attribute__((noinline)) 40*3cab2bb3Spatrickvoid access_memory(char *a) { 41*3cab2bb3Spatrick *a = 0; 42*3cab2bb3Spatrick} 43*3cab2bb3Spatrick 44*3cab2bb3Spatrick// Test the +load instrumentation. 45*3cab2bb3Spatrick// Because the +load methods are invoked before anything else is initialized, 46*3cab2bb3Spatrick// it makes little sense to wrap the code below into a gTest test case. 47*3cab2bb3Spatrick// If AddressSanitizer doesn't instrument the +load method below correctly, 48*3cab2bb3Spatrick// everything will just crash. 49*3cab2bb3Spatrick 50*3cab2bb3Spatrickchar kStartupStr[] = 51*3cab2bb3Spatrick "If your test didn't crash, AddressSanitizer is instrumenting " 52*3cab2bb3Spatrick "the +load methods correctly."; 53*3cab2bb3Spatrick 54*3cab2bb3Spatrick@interface LoadSomething : NSObject { 55*3cab2bb3Spatrick} 56*3cab2bb3Spatrick@end 57*3cab2bb3Spatrick 58*3cab2bb3Spatrick@implementation LoadSomething 59*3cab2bb3Spatrick 60*3cab2bb3Spatrick+(void) load { 61*3cab2bb3Spatrick for (size_t i = 0; i < strlen(kStartupStr); i++) { 62*3cab2bb3Spatrick access_memory(&kStartupStr[i]); // make sure no optimizations occur. 63*3cab2bb3Spatrick } 64*3cab2bb3Spatrick // Don't print anything here not to interfere with the death tests. 65*3cab2bb3Spatrick} 66*3cab2bb3Spatrick 67*3cab2bb3Spatrick@end 68*3cab2bb3Spatrick 69*3cab2bb3Spatrickvoid worker_do_alloc(int size) { 70*3cab2bb3Spatrick char * volatile mem = (char * volatile)malloc(size); 71*3cab2bb3Spatrick mem[0] = 0; // Ok 72*3cab2bb3Spatrick free(mem); 73*3cab2bb3Spatrick} 74*3cab2bb3Spatrick 75*3cab2bb3Spatrickvoid worker_do_crash(int size) { 76*3cab2bb3Spatrick char * volatile mem = (char * volatile)malloc(size); 77*3cab2bb3Spatrick access_memory(&mem[size]); // BOOM 78*3cab2bb3Spatrick free(mem); 79*3cab2bb3Spatrick} 80*3cab2bb3Spatrick 81*3cab2bb3Spatrick// Used by the GCD tests to avoid a race between the worker thread reporting a 82*3cab2bb3Spatrick// memory error and the main thread which may exit with exit code 0 before 83*3cab2bb3Spatrick// that. 84*3cab2bb3Spatrickvoid wait_forever() { 85*3cab2bb3Spatrick volatile bool infinite = true; 86*3cab2bb3Spatrick while (infinite) pthread_yield_np(); 87*3cab2bb3Spatrick} 88*3cab2bb3Spatrick 89*3cab2bb3Spatrick// Tests for the Grand Central Dispatch. See 90*3cab2bb3Spatrick// http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html 91*3cab2bb3Spatrick// for the reference. 92*3cab2bb3Spatrickvoid TestGCDDispatchAsync() { 93*3cab2bb3Spatrick dispatch_queue_t queue = dispatch_get_global_queue(0, 0); 94*3cab2bb3Spatrick dispatch_block_t block = ^{ worker_do_crash(1024); }; 95*3cab2bb3Spatrick // dispatch_async() runs the task on a worker thread that does not go through 96*3cab2bb3Spatrick // pthread_create(). We need to verify that AddressSanitizer notices that the 97*3cab2bb3Spatrick // thread has started. 98*3cab2bb3Spatrick dispatch_async(queue, block); 99*3cab2bb3Spatrick wait_forever(); 100*3cab2bb3Spatrick} 101*3cab2bb3Spatrick 102*3cab2bb3Spatrickvoid TestGCDDispatchSync() { 103*3cab2bb3Spatrick dispatch_queue_t queue = dispatch_get_global_queue(2, 0); 104*3cab2bb3Spatrick dispatch_block_t block = ^{ worker_do_crash(1024); }; 105*3cab2bb3Spatrick // dispatch_sync() runs the task on a worker thread that does not go through 106*3cab2bb3Spatrick // pthread_create(). We need to verify that AddressSanitizer notices that the 107*3cab2bb3Spatrick // thread has started. 108*3cab2bb3Spatrick dispatch_sync(queue, block); 109*3cab2bb3Spatrick wait_forever(); 110*3cab2bb3Spatrick} 111*3cab2bb3Spatrick 112*3cab2bb3Spatrick// libdispatch spawns a rather small number of threads and reuses them. We need 113*3cab2bb3Spatrick// to make sure AddressSanitizer handles the reusing correctly. 114*3cab2bb3Spatrickvoid TestGCDReuseWqthreadsAsync() { 115*3cab2bb3Spatrick dispatch_queue_t queue = dispatch_get_global_queue(0, 0); 116*3cab2bb3Spatrick dispatch_block_t block_alloc = ^{ worker_do_alloc(1024); }; 117*3cab2bb3Spatrick dispatch_block_t block_crash = ^{ worker_do_crash(1024); }; 118*3cab2bb3Spatrick for (int i = 0; i < 100; i++) { 119*3cab2bb3Spatrick dispatch_async(queue, block_alloc); 120*3cab2bb3Spatrick } 121*3cab2bb3Spatrick dispatch_async(queue, block_crash); 122*3cab2bb3Spatrick wait_forever(); 123*3cab2bb3Spatrick} 124*3cab2bb3Spatrick 125*3cab2bb3Spatrick// Try to trigger abnormal behaviour of dispatch_sync() being unhandled by us. 126*3cab2bb3Spatrickvoid TestGCDReuseWqthreadsSync() { 127*3cab2bb3Spatrick dispatch_queue_t queue[4]; 128*3cab2bb3Spatrick queue[0] = dispatch_get_global_queue(2, 0); 129*3cab2bb3Spatrick queue[1] = dispatch_get_global_queue(0, 0); 130*3cab2bb3Spatrick queue[2] = dispatch_get_global_queue(-2, 0); 131*3cab2bb3Spatrick queue[3] = dispatch_queue_create("my_queue", NULL); 132*3cab2bb3Spatrick dispatch_block_t block_alloc = ^{ worker_do_alloc(1024); }; 133*3cab2bb3Spatrick dispatch_block_t block_crash = ^{ worker_do_crash(1024); }; 134*3cab2bb3Spatrick for (int i = 0; i < 1000; i++) { 135*3cab2bb3Spatrick dispatch_sync(queue[i % 4], block_alloc); 136*3cab2bb3Spatrick } 137*3cab2bb3Spatrick dispatch_sync(queue[3], block_crash); 138*3cab2bb3Spatrick wait_forever(); 139*3cab2bb3Spatrick} 140*3cab2bb3Spatrick 141*3cab2bb3Spatrickvoid TestGCDDispatchAfter() { 142*3cab2bb3Spatrick dispatch_queue_t queue = dispatch_get_global_queue(0, 0); 143*3cab2bb3Spatrick dispatch_block_t block_crash = ^{ worker_do_crash(1024); }; 144*3cab2bb3Spatrick // Schedule the event one second from the current time. 145*3cab2bb3Spatrick dispatch_time_t milestone = 146*3cab2bb3Spatrick dispatch_time(DISPATCH_TIME_NOW, 1LL * NSEC_PER_SEC); 147*3cab2bb3Spatrick dispatch_after(milestone, queue, block_crash); 148*3cab2bb3Spatrick wait_forever(); 149*3cab2bb3Spatrick} 150*3cab2bb3Spatrick 151*3cab2bb3Spatrickvoid worker_do_deallocate(void *ptr) { 152*3cab2bb3Spatrick free(ptr); 153*3cab2bb3Spatrick} 154*3cab2bb3Spatrick 155*3cab2bb3Spatrickvoid CallFreeOnWorkqueue(void *tsd) { 156*3cab2bb3Spatrick dispatch_queue_t queue = dispatch_get_global_queue(0, 0); 157*3cab2bb3Spatrick dispatch_block_t block_dealloc = ^{ worker_do_deallocate(tsd); }; 158*3cab2bb3Spatrick dispatch_async(queue, block_dealloc); 159*3cab2bb3Spatrick // Do not wait for the worker to free the memory -- nobody is going to touch 160*3cab2bb3Spatrick // it. 161*3cab2bb3Spatrick} 162*3cab2bb3Spatrick 163*3cab2bb3Spatrickvoid TestGCDSourceEvent() { 164*3cab2bb3Spatrick dispatch_queue_t queue = dispatch_get_global_queue(0, 0); 165*3cab2bb3Spatrick dispatch_source_t timer = 166*3cab2bb3Spatrick dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); 167*3cab2bb3Spatrick // Schedule the timer one second from the current time. 168*3cab2bb3Spatrick dispatch_time_t milestone = 169*3cab2bb3Spatrick dispatch_time(DISPATCH_TIME_NOW, 1LL * NSEC_PER_SEC); 170*3cab2bb3Spatrick 171*3cab2bb3Spatrick dispatch_source_set_timer(timer, milestone, DISPATCH_TIME_FOREVER, 0); 172*3cab2bb3Spatrick char * volatile mem = (char * volatile)malloc(10); 173*3cab2bb3Spatrick dispatch_source_set_event_handler(timer, ^{ 174*3cab2bb3Spatrick access_memory(&mem[10]); 175*3cab2bb3Spatrick }); 176*3cab2bb3Spatrick dispatch_resume(timer); 177*3cab2bb3Spatrick wait_forever(); 178*3cab2bb3Spatrick} 179*3cab2bb3Spatrick 180*3cab2bb3Spatrickvoid TestGCDSourceCancel() { 181*3cab2bb3Spatrick dispatch_queue_t queue = dispatch_get_global_queue(0, 0); 182*3cab2bb3Spatrick dispatch_source_t timer = 183*3cab2bb3Spatrick dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); 184*3cab2bb3Spatrick // Schedule the timer one second from the current time. 185*3cab2bb3Spatrick dispatch_time_t milestone = 186*3cab2bb3Spatrick dispatch_time(DISPATCH_TIME_NOW, 1LL * NSEC_PER_SEC); 187*3cab2bb3Spatrick 188*3cab2bb3Spatrick dispatch_source_set_timer(timer, milestone, DISPATCH_TIME_FOREVER, 0); 189*3cab2bb3Spatrick char * volatile mem = (char * volatile)malloc(10); 190*3cab2bb3Spatrick // Both dispatch_source_set_cancel_handler() and 191*3cab2bb3Spatrick // dispatch_source_set_event_handler() use dispatch_barrier_async_f(). 192*3cab2bb3Spatrick // It's tricky to test dispatch_source_set_cancel_handler() separately, 193*3cab2bb3Spatrick // so we test both here. 194*3cab2bb3Spatrick dispatch_source_set_event_handler(timer, ^{ 195*3cab2bb3Spatrick dispatch_source_cancel(timer); 196*3cab2bb3Spatrick }); 197*3cab2bb3Spatrick dispatch_source_set_cancel_handler(timer, ^{ 198*3cab2bb3Spatrick access_memory(&mem[10]); 199*3cab2bb3Spatrick }); 200*3cab2bb3Spatrick dispatch_resume(timer); 201*3cab2bb3Spatrick wait_forever(); 202*3cab2bb3Spatrick} 203*3cab2bb3Spatrick 204*3cab2bb3Spatrickvoid TestGCDGroupAsync() { 205*3cab2bb3Spatrick dispatch_queue_t queue = dispatch_get_global_queue(0, 0); 206*3cab2bb3Spatrick dispatch_group_t group = dispatch_group_create(); 207*3cab2bb3Spatrick char * volatile mem = (char * volatile)malloc(10); 208*3cab2bb3Spatrick dispatch_group_async(group, queue, ^{ 209*3cab2bb3Spatrick access_memory(&mem[10]); 210*3cab2bb3Spatrick }); 211*3cab2bb3Spatrick dispatch_group_wait(group, DISPATCH_TIME_FOREVER); 212*3cab2bb3Spatrick wait_forever(); 213*3cab2bb3Spatrick} 214*3cab2bb3Spatrick 215*3cab2bb3Spatrick@interface FixedArray : NSObject { 216*3cab2bb3Spatrick int items[10]; 217*3cab2bb3Spatrick} 218*3cab2bb3Spatrick@end 219*3cab2bb3Spatrick 220*3cab2bb3Spatrick@implementation FixedArray 221*3cab2bb3Spatrick-(int) access: (int)index { 222*3cab2bb3Spatrick return items[index]; 223*3cab2bb3Spatrick} 224*3cab2bb3Spatrick@end 225*3cab2bb3Spatrick 226*3cab2bb3Spatrickvoid TestOOBNSObjects() { 227*3cab2bb3Spatrick id anObject = [FixedArray new]; 228*3cab2bb3Spatrick [anObject access:1]; 229*3cab2bb3Spatrick [anObject access:11]; 230*3cab2bb3Spatrick [anObject release]; 231*3cab2bb3Spatrick} 232*3cab2bb3Spatrick 233*3cab2bb3Spatrickvoid TestNSURLDeallocation() { 234*3cab2bb3Spatrick NSURL *base = 235*3cab2bb3Spatrick [[NSURL alloc] initWithString:@"file://localhost/Users/glider/Library/"]; 236*3cab2bb3Spatrick volatile NSURL *u = 237*3cab2bb3Spatrick [[NSURL alloc] initWithString:@"Saved Application State" 238*3cab2bb3Spatrick relativeToURL:base]; 239*3cab2bb3Spatrick [u release]; 240*3cab2bb3Spatrick [base release]; 241*3cab2bb3Spatrick} 242