• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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