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