]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/asan/tests/asan_mac_test_helpers.mm
Update compiler-rt to trunk r224034. This brings a number of new
[FreeBSD/FreeBSD.git] / contrib / compiler-rt / lib / asan / tests / asan_mac_test_helpers.mm
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.
14 void *CFAllocatorDefaultDoubleFree(void *unused) {
15   void *mem = CFAllocatorAllocate(kCFAllocatorDefault, 5, 0);
16   CFAllocatorDeallocate(kCFAllocatorDefault, mem);
17   CFAllocatorDeallocate(kCFAllocatorDefault, mem);
18   return 0;
19 }
20
21 void CFAllocatorSystemDefaultDoubleFree() {
22   void *mem = CFAllocatorAllocate(kCFAllocatorSystemDefault, 5, 0);
23   CFAllocatorDeallocate(kCFAllocatorSystemDefault, mem);
24   CFAllocatorDeallocate(kCFAllocatorSystemDefault, mem);
25 }
26
27 void CFAllocatorMallocDoubleFree() {
28   void *mem = CFAllocatorAllocate(kCFAllocatorMalloc, 5, 0);
29   CFAllocatorDeallocate(kCFAllocatorMalloc, mem);
30   CFAllocatorDeallocate(kCFAllocatorMalloc, mem);
31 }
32
33 void CFAllocatorMallocZoneDoubleFree() {
34   void *mem = CFAllocatorAllocate(kCFAllocatorMallocZone, 5, 0);
35   CFAllocatorDeallocate(kCFAllocatorMallocZone, mem);
36   CFAllocatorDeallocate(kCFAllocatorMallocZone, mem);
37 }
38
39 __attribute__((noinline))
40 void 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
50 char 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(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 @end
68
69 void worker_do_alloc(int size) {
70   char * volatile mem = (char * volatile)malloc(size);
71   mem[0] = 0; // Ok
72   free(mem);
73 }
74
75 void worker_do_crash(int size) {
76   char * volatile mem = (char * volatile)malloc(size);
77   access_memory(&mem[size]);  // BOOM
78   free(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.
84 void 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.
92 void 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
102 void 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.
114 void 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.
126 void 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
141 void 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
151 void worker_do_deallocate(void *ptr) {
152   free(ptr);
153 }
154
155 void 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
163 void 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(10);
173   dispatch_source_set_event_handler(timer, ^{
174     access_memory(&mem[10]);
175   });
176   dispatch_resume(timer);
177   wait_forever();
178 }
179
180 void 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(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(&mem[10]);
199   });
200   dispatch_resume(timer);
201   wait_forever();
202 }
203
204 void 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(10);
208   dispatch_group_async(group, queue, ^{
209     access_memory(&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
226 void TestOOBNSObjects() {
227   id anObject = [FixedArray new];
228   [anObject access:1];
229   [anObject access:11];
230   [anObject release];
231 }
232
233 void 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 }