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
TEST(AddressSanitizerMac,CFAllocatorDefaultDoubleFree)22 TEST(AddressSanitizerMac, CFAllocatorDefaultDoubleFree) {
23 EXPECT_DEATH(
24 CFAllocatorDefaultDoubleFree(NULL),
25 "attempting double-free");
26 }
27
CFAllocator_DoubleFreeOnPthread()28 void CFAllocator_DoubleFreeOnPthread() {
29 pthread_t child;
30 PTHREAD_CREATE(&child, NULL, CFAllocatorDefaultDoubleFree, NULL);
31 PTHREAD_JOIN(child, NULL); // Shouldn't be reached.
32 }
33
TEST(AddressSanitizerMac,CFAllocatorDefaultDoubleFree_ChildPhread)34 TEST(AddressSanitizerMac, CFAllocatorDefaultDoubleFree_ChildPhread) {
35 EXPECT_DEATH(CFAllocator_DoubleFreeOnPthread(), "attempting double-free");
36 }
37
38 namespace {
39
40 void *GLOB;
41
CFAllocatorAllocateToGlob(void * unused)42 void *CFAllocatorAllocateToGlob(void *unused) {
43 GLOB = CFAllocatorAllocate(NULL, 100, /*hint*/0);
44 return NULL;
45 }
46
CFAllocatorDeallocateFromGlob(void * unused)47 void *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
CFAllocator_PassMemoryToAnotherThread()54 void 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
TEST(AddressSanitizerMac,CFAllocator_PassMemoryToAnotherThread)62 TEST(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?
TEST(AddressSanitizerMac,DISABLED_CFAllocatorSystemDefaultDoubleFree)71 TEST(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.
TEST(AddressSanitizerMac,CFAllocatorMallocDoubleFree)78 TEST(AddressSanitizerMac, CFAllocatorMallocDoubleFree) {
79 EXPECT_DEATH(CFAllocatorMallocDoubleFree(), "attempting double-free");
80 }
81
TEST(AddressSanitizerMac,DISABLED_CFAllocatorMallocZoneDoubleFree)82 TEST(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).
TEST(AddressSanitizerMac,GCDDispatchAsync)89 TEST(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
TEST(AddressSanitizerMac,GCDDispatchSync)95 TEST(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
TEST(AddressSanitizerMac,GCDReuseWqthreadsAsync)102 TEST(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
TEST(AddressSanitizerMac,GCDReuseWqthreadsSync)108 TEST(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
TEST(AddressSanitizerMac,GCDDispatchAfter)114 TEST(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
TEST(AddressSanitizerMac,GCDSourceEvent)120 TEST(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
TEST(AddressSanitizerMac,GCDSourceCancel)126 TEST(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
TEST(AddressSanitizerMac,GCDGroupAsync)132 TEST(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
MallocIntrospectionLockWorker(void * _)138 void *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
MallocIntrospectionLockForker(void * _)152 void *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
TEST(AddressSanitizerMac,MallocIntrospectionLock)169 TEST(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
TSDAllocWorker(void * test_key)188 void *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
TEST(AddressSanitizerMac,DISABLED_TSDWorkqueueTest)196 TEST(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.
TEST(AddressSanitizerMac,CFStringCreateCopy)206 TEST(AddressSanitizerMac, CFStringCreateCopy) {
207 CFStringRef str = CFSTR("Hello world!\n");
208 CFStringRef str2 = CFStringCreateCopy(0, str);
209 EXPECT_EQ(str, str2);
210 }
211
TEST(AddressSanitizerMac,NSObjectOOB)212 TEST(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.
TEST(AddressSanitizerMac,NSURLDeallocation)220 TEST(AddressSanitizerMac, NSURLDeallocation) {
221 TestNSURLDeallocation();
222 }
223
224 // See https://github.com/google/sanitizers/issues/109.
TEST(AddressSanitizerMac,Mstats)225 TEST(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