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