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