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