brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.8 KiB · ddb50f8 Raw
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