diff options
author | Simon J. Gerraty <sjg@FreeBSD.org> | 2015-05-27 01:19:58 +0000 |
---|---|---|
committer | Simon J. Gerraty <sjg@FreeBSD.org> | 2015-05-27 01:19:58 +0000 |
commit | 98e0ffaefb0f241cda3a72395d3be04192ae0d47 (patch) | |
tree | 55c065b6730aaac2afb6c29933ee6ec5fa4c4249 /contrib/compiler-rt/lib/asan/tests/asan_mac_test_helpers.mm | |
parent | b17ff922d4072ae132ece458f5b5d74a236880ac (diff) | |
parent | e81032ad243db32b8fd615b2d55ee94b9f6a5b6a (diff) | |
download | src-98e0ffaefb0f241cda3a72395d3be04192ae0d47.tar.gz src-98e0ffaefb0f241cda3a72395d3be04192ae0d47.zip |
Merge sync of head
Notes
Notes:
svn path=/projects/bmake/; revision=283595
Diffstat (limited to 'contrib/compiler-rt/lib/asan/tests/asan_mac_test_helpers.mm')
-rw-r--r-- | contrib/compiler-rt/lib/asan/tests/asan_mac_test_helpers.mm | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/contrib/compiler-rt/lib/asan/tests/asan_mac_test_helpers.mm b/contrib/compiler-rt/lib/asan/tests/asan_mac_test_helpers.mm new file mode 100644 index 000000000000..a7e4b9d1928b --- /dev/null +++ b/contrib/compiler-rt/lib/asan/tests/asan_mac_test_helpers.mm @@ -0,0 +1,240 @@ +// Mac OS X 10.6 or higher only. +#include <dispatch/dispatch.h> +#include <pthread.h> // for pthread_yield_np() +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#import <CoreFoundation/CFBase.h> +#import <Foundation/NSObject.h> +#import <Foundation/NSURL.h> + +// This is a (void*)(void*) function so it can be passed to pthread_create. +void *CFAllocatorDefaultDoubleFree(void *unused) { + void *mem = CFAllocatorAllocate(kCFAllocatorDefault, 5, 0); + CFAllocatorDeallocate(kCFAllocatorDefault, mem); + CFAllocatorDeallocate(kCFAllocatorDefault, mem); + return 0; +} + +void CFAllocatorSystemDefaultDoubleFree() { + void *mem = CFAllocatorAllocate(kCFAllocatorSystemDefault, 5, 0); + CFAllocatorDeallocate(kCFAllocatorSystemDefault, mem); + CFAllocatorDeallocate(kCFAllocatorSystemDefault, mem); +} + +void CFAllocatorMallocDoubleFree() { + void *mem = CFAllocatorAllocate(kCFAllocatorMalloc, 5, 0); + CFAllocatorDeallocate(kCFAllocatorMalloc, mem); + CFAllocatorDeallocate(kCFAllocatorMalloc, mem); +} + +void CFAllocatorMallocZoneDoubleFree() { + void *mem = CFAllocatorAllocate(kCFAllocatorMallocZone, 5, 0); + CFAllocatorDeallocate(kCFAllocatorMallocZone, mem); + CFAllocatorDeallocate(kCFAllocatorMallocZone, mem); +} + +__attribute__((noinline)) +void access_memory(char *a) { + *a = 0; +} + +// Test the +load instrumentation. +// Because the +load methods are invoked before anything else is initialized, +// it makes little sense to wrap the code below into a gTest test case. +// If AddressSanitizer doesn't instrument the +load method below correctly, +// everything will just crash. + +char kStartupStr[] = + "If your test didn't crash, AddressSanitizer is instrumenting " + "the +load methods correctly."; + +@interface LoadSomething : NSObject { +} +@end + +@implementation LoadSomething + ++(void) load { + for (size_t i = 0; i < strlen(kStartupStr); i++) { + access_memory(&kStartupStr[i]); // make sure no optimizations occur. + } + // Don't print anything here not to interfere with the death tests. +} + +@end + +void worker_do_alloc(int size) { + char * volatile mem = (char * volatile)malloc(size); + mem[0] = 0; // Ok + free(mem); +} + +void worker_do_crash(int size) { + char * volatile mem = (char * volatile)malloc(size); + access_memory(&mem[size]); // BOOM + free(mem); +} + +// Used by the GCD tests to avoid a race between the worker thread reporting a +// memory error and the main thread which may exit with exit code 0 before +// that. +void wait_forever() { + volatile bool infinite = true; + while (infinite) pthread_yield_np(); +} + +// Tests for the Grand Central Dispatch. See +// http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html +// for the reference. +void TestGCDDispatchAsync() { + dispatch_queue_t queue = dispatch_get_global_queue(0, 0); + dispatch_block_t block = ^{ worker_do_crash(1024); }; + // dispatch_async() runs the task on a worker thread that does not go through + // pthread_create(). We need to verify that AddressSanitizer notices that the + // thread has started. + dispatch_async(queue, block); + wait_forever(); +} + +void TestGCDDispatchSync() { + dispatch_queue_t queue = dispatch_get_global_queue(2, 0); + dispatch_block_t block = ^{ worker_do_crash(1024); }; + // dispatch_sync() runs the task on a worker thread that does not go through + // pthread_create(). We need to verify that AddressSanitizer notices that the + // thread has started. + dispatch_sync(queue, block); + wait_forever(); +} + +// libdispatch spawns a rather small number of threads and reuses them. We need +// to make sure AddressSanitizer handles the reusing correctly. +void TestGCDReuseWqthreadsAsync() { + dispatch_queue_t queue = dispatch_get_global_queue(0, 0); + dispatch_block_t block_alloc = ^{ worker_do_alloc(1024); }; + dispatch_block_t block_crash = ^{ worker_do_crash(1024); }; + for (int i = 0; i < 100; i++) { + dispatch_async(queue, block_alloc); + } + dispatch_async(queue, block_crash); + wait_forever(); +} + +// Try to trigger abnormal behaviour of dispatch_sync() being unhandled by us. +void TestGCDReuseWqthreadsSync() { + dispatch_queue_t queue[4]; + queue[0] = dispatch_get_global_queue(2, 0); + queue[1] = dispatch_get_global_queue(0, 0); + queue[2] = dispatch_get_global_queue(-2, 0); + queue[3] = dispatch_queue_create("my_queue", NULL); + dispatch_block_t block_alloc = ^{ worker_do_alloc(1024); }; + dispatch_block_t block_crash = ^{ worker_do_crash(1024); }; + for (int i = 0; i < 1000; i++) { + dispatch_sync(queue[i % 4], block_alloc); + } + dispatch_sync(queue[3], block_crash); + wait_forever(); +} + +void TestGCDDispatchAfter() { + dispatch_queue_t queue = dispatch_get_global_queue(0, 0); + dispatch_block_t block_crash = ^{ worker_do_crash(1024); }; + // Schedule the event one second from the current time. + dispatch_time_t milestone = + dispatch_time(DISPATCH_TIME_NOW, 1LL * NSEC_PER_SEC); + dispatch_after(milestone, queue, block_crash); + wait_forever(); +} + +void worker_do_deallocate(void *ptr) { + free(ptr); +} + +void CallFreeOnWorkqueue(void *tsd) { + dispatch_queue_t queue = dispatch_get_global_queue(0, 0); + dispatch_block_t block_dealloc = ^{ worker_do_deallocate(tsd); }; + dispatch_async(queue, block_dealloc); + // Do not wait for the worker to free the memory -- nobody is going to touch + // it. +} + +void TestGCDSourceEvent() { + dispatch_queue_t queue = dispatch_get_global_queue(0, 0); + dispatch_source_t timer = + dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); + // Schedule the timer one second from the current time. + dispatch_time_t milestone = + dispatch_time(DISPATCH_TIME_NOW, 1LL * NSEC_PER_SEC); + + dispatch_source_set_timer(timer, milestone, DISPATCH_TIME_FOREVER, 0); + char * volatile mem = (char * volatile)malloc(10); + dispatch_source_set_event_handler(timer, ^{ + access_memory(&mem[10]); + }); + dispatch_resume(timer); + wait_forever(); +} + +void TestGCDSourceCancel() { + dispatch_queue_t queue = dispatch_get_global_queue(0, 0); + dispatch_source_t timer = + dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); + // Schedule the timer one second from the current time. + dispatch_time_t milestone = + dispatch_time(DISPATCH_TIME_NOW, 1LL * NSEC_PER_SEC); + + dispatch_source_set_timer(timer, milestone, DISPATCH_TIME_FOREVER, 0); + char * volatile mem = (char * volatile)malloc(10); + // Both dispatch_source_set_cancel_handler() and + // dispatch_source_set_event_handler() use dispatch_barrier_async_f(). + // It's tricky to test dispatch_source_set_cancel_handler() separately, + // so we test both here. + dispatch_source_set_event_handler(timer, ^{ + dispatch_source_cancel(timer); + }); + dispatch_source_set_cancel_handler(timer, ^{ + access_memory(&mem[10]); + }); + dispatch_resume(timer); + wait_forever(); +} + +void TestGCDGroupAsync() { + dispatch_queue_t queue = dispatch_get_global_queue(0, 0); + dispatch_group_t group = dispatch_group_create(); + char * volatile mem = (char * volatile)malloc(10); + dispatch_group_async(group, queue, ^{ + access_memory(&mem[10]); + }); + dispatch_group_wait(group, DISPATCH_TIME_FOREVER); + wait_forever(); +} + +@interface FixedArray : NSObject { + int items[10]; +} +@end + +@implementation FixedArray +-(int) access: (int)index { + return items[index]; +} +@end + +void TestOOBNSObjects() { + id anObject = [FixedArray new]; + [anObject access:1]; + [anObject access:11]; + [anObject release]; +} + +void TestNSURLDeallocation() { + NSURL *base = + [[NSURL alloc] initWithString:@"file://localhost/Users/glider/Library/"]; + volatile NSURL *u = + [[NSURL alloc] initWithString:@"Saved Application State" + relativeToURL:base]; + [u release]; +} |