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