aboutsummaryrefslogtreecommitdiff
path: root/contrib/compiler-rt/lib/asan/tests/asan_mac_test_helpers.mm
diff options
context:
space:
mode:
authorSimon J. Gerraty <sjg@FreeBSD.org>2015-05-27 01:19:58 +0000
committerSimon J. Gerraty <sjg@FreeBSD.org>2015-05-27 01:19:58 +0000
commit98e0ffaefb0f241cda3a72395d3be04192ae0d47 (patch)
tree55c065b6730aaac2afb6c29933ee6ec5fa4c4249 /contrib/compiler-rt/lib/asan/tests/asan_mac_test_helpers.mm
parentb17ff922d4072ae132ece458f5b5d74a236880ac (diff)
parente81032ad243db32b8fd615b2d55ee94b9f6a5b6a (diff)
downloadsrc-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.mm240
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];
+}