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