blob: dfa6d7596d742c1456b1371566d76cd44e8118b2 [file] [log] [blame]
Alexander Potapenko8c745fc2013-01-21 14:49:55 +00001//===-- 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.
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -0800219// See https://github.com/google/sanitizers/issues/70.
Alexander Potapenko8c745fc2013-01-21 14:49:55 +0000220TEST(AddressSanitizerMac, NSURLDeallocation) {
221 TestNSURLDeallocation();
222}
223
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -0800224// See https://github.com/google/sanitizers/issues/109.
Alexander Potapenko8c745fc2013-01-21 14:49:55 +0000225TEST(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