xref: /openbsd-src/gnu/llvm/compiler-rt/lib/asan/tests/asan_mac_test_helpers.mm (revision 3cab2bb3f667058bece8e38b12449a63a9d73c4b)
1*3cab2bb3Spatrick// Mac OS X 10.6 or higher only.
2*3cab2bb3Spatrick#include <dispatch/dispatch.h>
3*3cab2bb3Spatrick#include <pthread.h>  // for pthread_yield_np()
4*3cab2bb3Spatrick#include <stdio.h>
5*3cab2bb3Spatrick#include <stdlib.h>
6*3cab2bb3Spatrick#include <string.h>
7*3cab2bb3Spatrick#include <unistd.h>
8*3cab2bb3Spatrick
9*3cab2bb3Spatrick#import <CoreFoundation/CFBase.h>
10*3cab2bb3Spatrick#import <Foundation/NSObject.h>
11*3cab2bb3Spatrick#import <Foundation/NSURL.h>
12*3cab2bb3Spatrick
13*3cab2bb3Spatrick// This is a (void*)(void*) function so it can be passed to pthread_create.
14*3cab2bb3Spatrickvoid *CFAllocatorDefaultDoubleFree(void *unused) {
15*3cab2bb3Spatrick  void *mem = CFAllocatorAllocate(kCFAllocatorDefault, 5, 0);
16*3cab2bb3Spatrick  CFAllocatorDeallocate(kCFAllocatorDefault, mem);
17*3cab2bb3Spatrick  CFAllocatorDeallocate(kCFAllocatorDefault, mem);
18*3cab2bb3Spatrick  return 0;
19*3cab2bb3Spatrick}
20*3cab2bb3Spatrick
21*3cab2bb3Spatrickvoid CFAllocatorSystemDefaultDoubleFree() {
22*3cab2bb3Spatrick  void *mem = CFAllocatorAllocate(kCFAllocatorSystemDefault, 5, 0);
23*3cab2bb3Spatrick  CFAllocatorDeallocate(kCFAllocatorSystemDefault, mem);
24*3cab2bb3Spatrick  CFAllocatorDeallocate(kCFAllocatorSystemDefault, mem);
25*3cab2bb3Spatrick}
26*3cab2bb3Spatrick
27*3cab2bb3Spatrickvoid CFAllocatorMallocDoubleFree() {
28*3cab2bb3Spatrick  void *mem = CFAllocatorAllocate(kCFAllocatorMalloc, 5, 0);
29*3cab2bb3Spatrick  CFAllocatorDeallocate(kCFAllocatorMalloc, mem);
30*3cab2bb3Spatrick  CFAllocatorDeallocate(kCFAllocatorMalloc, mem);
31*3cab2bb3Spatrick}
32*3cab2bb3Spatrick
33*3cab2bb3Spatrickvoid CFAllocatorMallocZoneDoubleFree() {
34*3cab2bb3Spatrick  void *mem = CFAllocatorAllocate(kCFAllocatorMallocZone, 5, 0);
35*3cab2bb3Spatrick  CFAllocatorDeallocate(kCFAllocatorMallocZone, mem);
36*3cab2bb3Spatrick  CFAllocatorDeallocate(kCFAllocatorMallocZone, mem);
37*3cab2bb3Spatrick}
38*3cab2bb3Spatrick
39*3cab2bb3Spatrick__attribute__((noinline))
40*3cab2bb3Spatrickvoid access_memory(char *a) {
41*3cab2bb3Spatrick  *a = 0;
42*3cab2bb3Spatrick}
43*3cab2bb3Spatrick
44*3cab2bb3Spatrick// Test the +load instrumentation.
45*3cab2bb3Spatrick// Because the +load methods are invoked before anything else is initialized,
46*3cab2bb3Spatrick// it makes little sense to wrap the code below into a gTest test case.
47*3cab2bb3Spatrick// If AddressSanitizer doesn't instrument the +load method below correctly,
48*3cab2bb3Spatrick// everything will just crash.
49*3cab2bb3Spatrick
50*3cab2bb3Spatrickchar kStartupStr[] =
51*3cab2bb3Spatrick    "If your test didn't crash, AddressSanitizer is instrumenting "
52*3cab2bb3Spatrick    "the +load methods correctly.";
53*3cab2bb3Spatrick
54*3cab2bb3Spatrick@interface LoadSomething : NSObject {
55*3cab2bb3Spatrick}
56*3cab2bb3Spatrick@end
57*3cab2bb3Spatrick
58*3cab2bb3Spatrick@implementation LoadSomething
59*3cab2bb3Spatrick
60*3cab2bb3Spatrick+(void) load {
61*3cab2bb3Spatrick  for (size_t i = 0; i < strlen(kStartupStr); i++) {
62*3cab2bb3Spatrick    access_memory(&kStartupStr[i]);  // make sure no optimizations occur.
63*3cab2bb3Spatrick  }
64*3cab2bb3Spatrick  // Don't print anything here not to interfere with the death tests.
65*3cab2bb3Spatrick}
66*3cab2bb3Spatrick
67*3cab2bb3Spatrick@end
68*3cab2bb3Spatrick
69*3cab2bb3Spatrickvoid worker_do_alloc(int size) {
70*3cab2bb3Spatrick  char * volatile mem = (char * volatile)malloc(size);
71*3cab2bb3Spatrick  mem[0] = 0; // Ok
72*3cab2bb3Spatrick  free(mem);
73*3cab2bb3Spatrick}
74*3cab2bb3Spatrick
75*3cab2bb3Spatrickvoid worker_do_crash(int size) {
76*3cab2bb3Spatrick  char * volatile mem = (char * volatile)malloc(size);
77*3cab2bb3Spatrick  access_memory(&mem[size]);  // BOOM
78*3cab2bb3Spatrick  free(mem);
79*3cab2bb3Spatrick}
80*3cab2bb3Spatrick
81*3cab2bb3Spatrick// Used by the GCD tests to avoid a race between the worker thread reporting a
82*3cab2bb3Spatrick// memory error and the main thread which may exit with exit code 0 before
83*3cab2bb3Spatrick// that.
84*3cab2bb3Spatrickvoid wait_forever() {
85*3cab2bb3Spatrick  volatile bool infinite = true;
86*3cab2bb3Spatrick  while (infinite) pthread_yield_np();
87*3cab2bb3Spatrick}
88*3cab2bb3Spatrick
89*3cab2bb3Spatrick// Tests for the Grand Central Dispatch. See
90*3cab2bb3Spatrick// http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html
91*3cab2bb3Spatrick// for the reference.
92*3cab2bb3Spatrickvoid TestGCDDispatchAsync() {
93*3cab2bb3Spatrick  dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
94*3cab2bb3Spatrick  dispatch_block_t block = ^{ worker_do_crash(1024); };
95*3cab2bb3Spatrick  // dispatch_async() runs the task on a worker thread that does not go through
96*3cab2bb3Spatrick  // pthread_create(). We need to verify that AddressSanitizer notices that the
97*3cab2bb3Spatrick  // thread has started.
98*3cab2bb3Spatrick  dispatch_async(queue, block);
99*3cab2bb3Spatrick  wait_forever();
100*3cab2bb3Spatrick}
101*3cab2bb3Spatrick
102*3cab2bb3Spatrickvoid TestGCDDispatchSync() {
103*3cab2bb3Spatrick  dispatch_queue_t queue = dispatch_get_global_queue(2, 0);
104*3cab2bb3Spatrick  dispatch_block_t block = ^{ worker_do_crash(1024); };
105*3cab2bb3Spatrick  // dispatch_sync() runs the task on a worker thread that does not go through
106*3cab2bb3Spatrick  // pthread_create(). We need to verify that AddressSanitizer notices that the
107*3cab2bb3Spatrick  // thread has started.
108*3cab2bb3Spatrick  dispatch_sync(queue, block);
109*3cab2bb3Spatrick  wait_forever();
110*3cab2bb3Spatrick}
111*3cab2bb3Spatrick
112*3cab2bb3Spatrick// libdispatch spawns a rather small number of threads and reuses them. We need
113*3cab2bb3Spatrick// to make sure AddressSanitizer handles the reusing correctly.
114*3cab2bb3Spatrickvoid TestGCDReuseWqthreadsAsync() {
115*3cab2bb3Spatrick  dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
116*3cab2bb3Spatrick  dispatch_block_t block_alloc = ^{ worker_do_alloc(1024); };
117*3cab2bb3Spatrick  dispatch_block_t block_crash = ^{ worker_do_crash(1024); };
118*3cab2bb3Spatrick  for (int i = 0; i < 100; i++) {
119*3cab2bb3Spatrick    dispatch_async(queue, block_alloc);
120*3cab2bb3Spatrick  }
121*3cab2bb3Spatrick  dispatch_async(queue, block_crash);
122*3cab2bb3Spatrick  wait_forever();
123*3cab2bb3Spatrick}
124*3cab2bb3Spatrick
125*3cab2bb3Spatrick// Try to trigger abnormal behaviour of dispatch_sync() being unhandled by us.
126*3cab2bb3Spatrickvoid TestGCDReuseWqthreadsSync() {
127*3cab2bb3Spatrick  dispatch_queue_t queue[4];
128*3cab2bb3Spatrick  queue[0] = dispatch_get_global_queue(2, 0);
129*3cab2bb3Spatrick  queue[1] = dispatch_get_global_queue(0, 0);
130*3cab2bb3Spatrick  queue[2] = dispatch_get_global_queue(-2, 0);
131*3cab2bb3Spatrick  queue[3] = dispatch_queue_create("my_queue", NULL);
132*3cab2bb3Spatrick  dispatch_block_t block_alloc = ^{ worker_do_alloc(1024); };
133*3cab2bb3Spatrick  dispatch_block_t block_crash = ^{ worker_do_crash(1024); };
134*3cab2bb3Spatrick  for (int i = 0; i < 1000; i++) {
135*3cab2bb3Spatrick    dispatch_sync(queue[i % 4], block_alloc);
136*3cab2bb3Spatrick  }
137*3cab2bb3Spatrick  dispatch_sync(queue[3], block_crash);
138*3cab2bb3Spatrick  wait_forever();
139*3cab2bb3Spatrick}
140*3cab2bb3Spatrick
141*3cab2bb3Spatrickvoid TestGCDDispatchAfter() {
142*3cab2bb3Spatrick  dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
143*3cab2bb3Spatrick  dispatch_block_t block_crash = ^{ worker_do_crash(1024); };
144*3cab2bb3Spatrick  // Schedule the event one second from the current time.
145*3cab2bb3Spatrick  dispatch_time_t milestone =
146*3cab2bb3Spatrick      dispatch_time(DISPATCH_TIME_NOW, 1LL * NSEC_PER_SEC);
147*3cab2bb3Spatrick  dispatch_after(milestone, queue, block_crash);
148*3cab2bb3Spatrick  wait_forever();
149*3cab2bb3Spatrick}
150*3cab2bb3Spatrick
151*3cab2bb3Spatrickvoid worker_do_deallocate(void *ptr) {
152*3cab2bb3Spatrick  free(ptr);
153*3cab2bb3Spatrick}
154*3cab2bb3Spatrick
155*3cab2bb3Spatrickvoid CallFreeOnWorkqueue(void *tsd) {
156*3cab2bb3Spatrick  dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
157*3cab2bb3Spatrick  dispatch_block_t block_dealloc = ^{ worker_do_deallocate(tsd); };
158*3cab2bb3Spatrick  dispatch_async(queue, block_dealloc);
159*3cab2bb3Spatrick  // Do not wait for the worker to free the memory -- nobody is going to touch
160*3cab2bb3Spatrick  // it.
161*3cab2bb3Spatrick}
162*3cab2bb3Spatrick
163*3cab2bb3Spatrickvoid TestGCDSourceEvent() {
164*3cab2bb3Spatrick  dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
165*3cab2bb3Spatrick  dispatch_source_t timer =
166*3cab2bb3Spatrick      dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
167*3cab2bb3Spatrick  // Schedule the timer one second from the current time.
168*3cab2bb3Spatrick  dispatch_time_t milestone =
169*3cab2bb3Spatrick      dispatch_time(DISPATCH_TIME_NOW, 1LL * NSEC_PER_SEC);
170*3cab2bb3Spatrick
171*3cab2bb3Spatrick  dispatch_source_set_timer(timer, milestone, DISPATCH_TIME_FOREVER, 0);
172*3cab2bb3Spatrick  char * volatile mem = (char * volatile)malloc(10);
173*3cab2bb3Spatrick  dispatch_source_set_event_handler(timer, ^{
174*3cab2bb3Spatrick    access_memory(&mem[10]);
175*3cab2bb3Spatrick  });
176*3cab2bb3Spatrick  dispatch_resume(timer);
177*3cab2bb3Spatrick  wait_forever();
178*3cab2bb3Spatrick}
179*3cab2bb3Spatrick
180*3cab2bb3Spatrickvoid TestGCDSourceCancel() {
181*3cab2bb3Spatrick  dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
182*3cab2bb3Spatrick  dispatch_source_t timer =
183*3cab2bb3Spatrick      dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
184*3cab2bb3Spatrick  // Schedule the timer one second from the current time.
185*3cab2bb3Spatrick  dispatch_time_t milestone =
186*3cab2bb3Spatrick      dispatch_time(DISPATCH_TIME_NOW, 1LL * NSEC_PER_SEC);
187*3cab2bb3Spatrick
188*3cab2bb3Spatrick  dispatch_source_set_timer(timer, milestone, DISPATCH_TIME_FOREVER, 0);
189*3cab2bb3Spatrick  char * volatile mem = (char * volatile)malloc(10);
190*3cab2bb3Spatrick  // Both dispatch_source_set_cancel_handler() and
191*3cab2bb3Spatrick  // dispatch_source_set_event_handler() use dispatch_barrier_async_f().
192*3cab2bb3Spatrick  // It's tricky to test dispatch_source_set_cancel_handler() separately,
193*3cab2bb3Spatrick  // so we test both here.
194*3cab2bb3Spatrick  dispatch_source_set_event_handler(timer, ^{
195*3cab2bb3Spatrick    dispatch_source_cancel(timer);
196*3cab2bb3Spatrick  });
197*3cab2bb3Spatrick  dispatch_source_set_cancel_handler(timer, ^{
198*3cab2bb3Spatrick    access_memory(&mem[10]);
199*3cab2bb3Spatrick  });
200*3cab2bb3Spatrick  dispatch_resume(timer);
201*3cab2bb3Spatrick  wait_forever();
202*3cab2bb3Spatrick}
203*3cab2bb3Spatrick
204*3cab2bb3Spatrickvoid TestGCDGroupAsync() {
205*3cab2bb3Spatrick  dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
206*3cab2bb3Spatrick  dispatch_group_t group = dispatch_group_create();
207*3cab2bb3Spatrick  char * volatile mem = (char * volatile)malloc(10);
208*3cab2bb3Spatrick  dispatch_group_async(group, queue, ^{
209*3cab2bb3Spatrick    access_memory(&mem[10]);
210*3cab2bb3Spatrick  });
211*3cab2bb3Spatrick  dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
212*3cab2bb3Spatrick  wait_forever();
213*3cab2bb3Spatrick}
214*3cab2bb3Spatrick
215*3cab2bb3Spatrick@interface FixedArray : NSObject {
216*3cab2bb3Spatrick  int items[10];
217*3cab2bb3Spatrick}
218*3cab2bb3Spatrick@end
219*3cab2bb3Spatrick
220*3cab2bb3Spatrick@implementation FixedArray
221*3cab2bb3Spatrick-(int) access: (int)index {
222*3cab2bb3Spatrick  return items[index];
223*3cab2bb3Spatrick}
224*3cab2bb3Spatrick@end
225*3cab2bb3Spatrick
226*3cab2bb3Spatrickvoid TestOOBNSObjects() {
227*3cab2bb3Spatrick  id anObject = [FixedArray new];
228*3cab2bb3Spatrick  [anObject access:1];
229*3cab2bb3Spatrick  [anObject access:11];
230*3cab2bb3Spatrick  [anObject release];
231*3cab2bb3Spatrick}
232*3cab2bb3Spatrick
233*3cab2bb3Spatrickvoid TestNSURLDeallocation() {
234*3cab2bb3Spatrick  NSURL *base =
235*3cab2bb3Spatrick      [[NSURL alloc] initWithString:@"file://localhost/Users/glider/Library/"];
236*3cab2bb3Spatrick  volatile NSURL *u =
237*3cab2bb3Spatrick      [[NSURL alloc] initWithString:@"Saved Application State"
238*3cab2bb3Spatrick                     relativeToURL:base];
239*3cab2bb3Spatrick  [u release];
240*3cab2bb3Spatrick  [base release];
241*3cab2bb3Spatrick}
242