1//===-- asan_test_mac.cc --------------------------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is a part of AddressSanitizer, an address sanity checker.
11//
12//===----------------------------------------------------------------------===//
13
14#include "asan_test_utils.h"
15
16#include "asan_mac_test.h"
17
18#include <malloc/malloc.h>
19#include <AvailabilityMacros.h>  // For MAC_OS_X_VERSION_*
20#include <CoreFoundation/CFString.h>
21
22TEST(AddressSanitizerMac, CFAllocatorDefaultDoubleFree) {
23  EXPECT_DEATH(
24      CFAllocatorDefaultDoubleFree(NULL),
25      "attempting double-free");
26}
27
28void CFAllocator_DoubleFreeOnPthread() {
29  pthread_t child;
30  PTHREAD_CREATE(&child, NULL, CFAllocatorDefaultDoubleFree, NULL);
31  PTHREAD_JOIN(child, NULL);  // Shouldn't be reached.
32}
33
34TEST(AddressSanitizerMac, CFAllocatorDefaultDoubleFree_ChildPhread) {
35  EXPECT_DEATH(CFAllocator_DoubleFreeOnPthread(), "attempting double-free");
36}
37
38namespace {
39
40void *GLOB;
41
42void *CFAllocatorAllocateToGlob(void *unused) {
43  GLOB = CFAllocatorAllocate(NULL, 100, /*hint*/0);
44  return NULL;
45}
46
47void *CFAllocatorDeallocateFromGlob(void *unused) {
48  char *p = (char*)GLOB;
49  p[100] = 'A';  // ASan should report an error here.
50  CFAllocatorDeallocate(NULL, GLOB);
51  return NULL;
52}
53
54void CFAllocator_PassMemoryToAnotherThread() {
55  pthread_t th1, th2;
56  PTHREAD_CREATE(&th1, NULL, CFAllocatorAllocateToGlob, NULL);
57  PTHREAD_JOIN(th1, NULL);
58  PTHREAD_CREATE(&th2, NULL, CFAllocatorDeallocateFromGlob, NULL);
59  PTHREAD_JOIN(th2, NULL);
60}
61
62TEST(AddressSanitizerMac, CFAllocator_PassMemoryToAnotherThread) {
63  EXPECT_DEATH(CFAllocator_PassMemoryToAnotherThread(),
64               "heap-buffer-overflow");
65}
66
67}  // namespace
68
69// TODO(glider): figure out whether we still need these tests. Is it correct
70// to intercept the non-default CFAllocators?
71TEST(AddressSanitizerMac, DISABLED_CFAllocatorSystemDefaultDoubleFree) {
72  EXPECT_DEATH(
73      CFAllocatorSystemDefaultDoubleFree(),
74      "attempting double-free");
75}
76
77// We're intercepting malloc, so kCFAllocatorMalloc is routed to ASan.
78TEST(AddressSanitizerMac, CFAllocatorMallocDoubleFree) {
79  EXPECT_DEATH(CFAllocatorMallocDoubleFree(), "attempting double-free");
80}
81
82TEST(AddressSanitizerMac, DISABLED_CFAllocatorMallocZoneDoubleFree) {
83  EXPECT_DEATH(CFAllocatorMallocZoneDoubleFree(), "attempting double-free");
84}
85
86// For libdispatch tests below we check that ASan got to the shadow byte
87// legend, i.e. managed to print the thread stacks (this almost certainly
88// means that the libdispatch task creation has been intercepted correctly).
89TEST(AddressSanitizerMac, GCDDispatchAsync) {
90  // Make sure the whole ASan report is printed, i.e. that we don't die
91  // on a CHECK.
92  EXPECT_DEATH(TestGCDDispatchAsync(), "Shadow byte legend");
93}
94
95TEST(AddressSanitizerMac, GCDDispatchSync) {
96  // Make sure the whole ASan report is printed, i.e. that we don't die
97  // on a CHECK.
98  EXPECT_DEATH(TestGCDDispatchSync(), "Shadow byte legend");
99}
100
101
102TEST(AddressSanitizerMac, GCDReuseWqthreadsAsync) {
103  // Make sure the whole ASan report is printed, i.e. that we don't die
104  // on a CHECK.
105  EXPECT_DEATH(TestGCDReuseWqthreadsAsync(), "Shadow byte legend");
106}
107
108TEST(AddressSanitizerMac, GCDReuseWqthreadsSync) {
109  // Make sure the whole ASan report is printed, i.e. that we don't die
110  // on a CHECK.
111  EXPECT_DEATH(TestGCDReuseWqthreadsSync(), "Shadow byte legend");
112}
113
114TEST(AddressSanitizerMac, GCDDispatchAfter) {
115  // Make sure the whole ASan report is printed, i.e. that we don't die
116  // on a CHECK.
117  EXPECT_DEATH(TestGCDDispatchAfter(), "Shadow byte legend");
118}
119
120TEST(AddressSanitizerMac, GCDSourceEvent) {
121  // Make sure the whole ASan report is printed, i.e. that we don't die
122  // on a CHECK.
123  EXPECT_DEATH(TestGCDSourceEvent(), "Shadow byte legend");
124}
125
126TEST(AddressSanitizerMac, GCDSourceCancel) {
127  // Make sure the whole ASan report is printed, i.e. that we don't die
128  // on a CHECK.
129  EXPECT_DEATH(TestGCDSourceCancel(), "Shadow byte legend");
130}
131
132TEST(AddressSanitizerMac, GCDGroupAsync) {
133  // Make sure the whole ASan report is printed, i.e. that we don't die
134  // on a CHECK.
135  EXPECT_DEATH(TestGCDGroupAsync(), "Shadow byte legend");
136}
137
138void *MallocIntrospectionLockWorker(void *_) {
139  const int kNumPointers = 100;
140  int i;
141  void *pointers[kNumPointers];
142  for (i = 0; i < kNumPointers; i++) {
143    pointers[i] = malloc(i + 1);
144  }
145  for (i = 0; i < kNumPointers; i++) {
146    free(pointers[i]);
147  }
148
149  return NULL;
150}
151
152void *MallocIntrospectionLockForker(void *_) {
153  pid_t result = fork();
154  if (result == -1) {
155    perror("fork");
156  }
157  assert(result != -1);
158  if (result == 0) {
159    // Call malloc in the child process to make sure we won't deadlock.
160    void *ptr = malloc(42);
161    free(ptr);
162    exit(0);
163  } else {
164    // Return in the parent process.
165    return NULL;
166  }
167}
168
169TEST(AddressSanitizerMac, MallocIntrospectionLock) {
170  // Incorrect implementation of force_lock and force_unlock in our malloc zone
171  // will cause forked processes to deadlock.
172  // TODO(glider): need to detect that none of the child processes deadlocked.
173  const int kNumWorkers = 5, kNumIterations = 100;
174  int i, iter;
175  for (iter = 0; iter < kNumIterations; iter++) {
176    pthread_t workers[kNumWorkers], forker;
177    for (i = 0; i < kNumWorkers; i++) {
178      PTHREAD_CREATE(&workers[i], 0, MallocIntrospectionLockWorker, 0);
179    }
180    PTHREAD_CREATE(&forker, 0, MallocIntrospectionLockForker, 0);
181    for (i = 0; i < kNumWorkers; i++) {
182      PTHREAD_JOIN(workers[i], 0);
183    }
184    PTHREAD_JOIN(forker, 0);
185  }
186}
187
188void *TSDAllocWorker(void *test_key) {
189  if (test_key) {
190    void *mem = malloc(10);
191    pthread_setspecific(*(pthread_key_t*)test_key, mem);
192  }
193  return NULL;
194}
195
196TEST(AddressSanitizerMac, DISABLED_TSDWorkqueueTest) {
197  pthread_t th;
198  pthread_key_t test_key;
199  pthread_key_create(&test_key, CallFreeOnWorkqueue);
200  PTHREAD_CREATE(&th, NULL, TSDAllocWorker, &test_key);
201  PTHREAD_JOIN(th, NULL);
202  pthread_key_delete(test_key);
203}
204
205// Test that CFStringCreateCopy does not copy constant strings.
206TEST(AddressSanitizerMac, CFStringCreateCopy) {
207  CFStringRef str = CFSTR("Hello world!\n");
208  CFStringRef str2 = CFStringCreateCopy(0, str);
209  EXPECT_EQ(str, str2);
210}
211
212TEST(AddressSanitizerMac, NSObjectOOB) {
213  // Make sure that our allocators are used for NSObjects.
214  EXPECT_DEATH(TestOOBNSObjects(), "heap-buffer-overflow");
215}
216
217// Make sure that correct pointer is passed to free() when deallocating a
218// NSURL object.
219// See https://github.com/google/sanitizers/issues/70.
220TEST(AddressSanitizerMac, NSURLDeallocation) {
221  TestNSURLDeallocation();
222}
223
224// See https://github.com/google/sanitizers/issues/109.
225TEST(AddressSanitizerMac, Mstats) {
226  malloc_statistics_t stats1, stats2;
227  malloc_zone_statistics(/*all zones*/NULL, &stats1);
228  const size_t kMallocSize = 100000;
229  void *alloc = Ident(malloc(kMallocSize));
230  malloc_zone_statistics(/*all zones*/NULL, &stats2);
231  EXPECT_GT(stats2.blocks_in_use, stats1.blocks_in_use);
232  EXPECT_GE(stats2.size_in_use - stats1.size_in_use, kMallocSize);
233  free(alloc);
234  // Even the default OSX allocator may not change the stats after free().
235}
236
237