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@end
57
58@implementation LoadSomething
59
60+(void) load {
61 for (size_t i = 0; i < strlen(s: kStartupStr); i++) {
62 access_memory(a: &kStartupStr[i]); // make sure no optimizations occur.
63 }
64 // Don't print anything here not to interfere with the death tests.
65}
66
67@end
68
69void worker_do_alloc(int size) {
70 char * volatile mem = (char * volatile)malloc(size: size);
71 mem[0] = 0; // Ok
72 free(ptr: mem);
73}
74
75void worker_do_crash(int size) {
76 char * volatile mem = (char * volatile)malloc(size: size);
77 access_memory(a: &mem[size]); // BOOM
78 free(ptr: mem);
79}
80
81// Used by the GCD tests to avoid a race between the worker thread reporting a
82// memory error and the main thread which may exit with exit code 0 before
83// that.
84void wait_forever() {
85 volatile bool infinite = true;
86 while (infinite) pthread_yield_np();
87}
88
89// Tests for the Grand Central Dispatch. See
90// http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html
91// 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 through
96 // pthread_create(). We need to verify that AddressSanitizer notices that the
97 // 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 through
106 // pthread_create(). We need to verify that AddressSanitizer notices that the
107 // 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 need
113// 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 worker_do_deallocate(void *ptr) {
152 free(ptr: ptr);
153}
154
155void CallFreeOnWorkqueue(void *tsd) {
156 dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
157 dispatch_block_t block_dealloc = ^{ worker_do_deallocate(tsd); };
158 dispatch_async(queue, block_dealloc);
159 // Do not wait for the worker to free the memory -- nobody is going to touch
160 // it.
161}
162
163void TestGCDSourceEvent() {
164 dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
165 dispatch_source_t timer =
166 dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
167 // Schedule the timer one second from the current time.
168 dispatch_time_t milestone =
169 dispatch_time(DISPATCH_TIME_NOW, 1LL * NSEC_PER_SEC);
170
171 dispatch_source_set_timer(timer, milestone, DISPATCH_TIME_FOREVER, 0);
172 char * volatile mem = (char * volatile)malloc(size: 10);
173 dispatch_source_set_event_handler(timer, ^{
174 access_memory(a: &mem[10]);
175 });
176 dispatch_resume(timer);
177 wait_forever();
178}
179
180void TestGCDSourceCancel() {
181 dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
182 dispatch_source_t timer =
183 dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
184 // Schedule the timer one second from the current time.
185 dispatch_time_t milestone =
186 dispatch_time(DISPATCH_TIME_NOW, 1LL * NSEC_PER_SEC);
187
188 dispatch_source_set_timer(timer, milestone, DISPATCH_TIME_FOREVER, 0);
189 char * volatile mem = (char * volatile)malloc(size: 10);
190 // Both dispatch_source_set_cancel_handler() and
191 // dispatch_source_set_event_handler() use dispatch_barrier_async_f().
192 // It's tricky to test dispatch_source_set_cancel_handler() separately,
193 // so we test both here.
194 dispatch_source_set_event_handler(timer, ^{
195 dispatch_source_cancel(timer);
196 });
197 dispatch_source_set_cancel_handler(timer, ^{
198 access_memory(a: &mem[10]);
199 });
200 dispatch_resume(timer);
201 wait_forever();
202}
203
204void TestGCDGroupAsync() {
205 dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
206 dispatch_group_t group = dispatch_group_create();
207 char * volatile mem = (char * volatile)malloc(size: 10);
208 dispatch_group_async(group, queue, ^{
209 access_memory(a: &mem[10]);
210 });
211 dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
212 wait_forever();
213}
214
215@interface FixedArray : NSObject {
216 int items[10];
217}
218@end
219
220@implementation FixedArray
221-(int) access: (int)index {
222 return items[index];
223}
224@end
225
226void TestOOBNSObjects() {
227 id anObject = [FixedArray new];
228 [anObject access:1];
229 [anObject access:11];
230 [anObject release];
231}
232
233void TestNSURLDeallocation() {
234 NSURL *base =
235 [[NSURL alloc] initWithString:@"file://localhost/Users/glider/Library/"];
236 volatile NSURL *u =
237 [[NSURL alloc] initWithString:@"Saved Application State"
238 relativeToURL:base];
239 [u release];
240 [base release];
241}
242

source code of compiler-rt/lib/asan/tests/asan_mac_test_helpers.mm