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 21 TEST(AddressSanitizerMac, CFAllocatorDefaultDoubleFree) { 22 EXPECT_DEATH( 23 CFAllocatorDefaultDoubleFree(NULL), 24 "attempting double-free"); 25 } 26 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 33 TEST(AddressSanitizerMac, CFAllocatorDefaultDoubleFree_ChildPhread) { 34 EXPECT_DEATH(CFAllocator_DoubleFreeOnPthread(), "attempting double-free"); 35 } 36 37 namespace { 38 39 void *GLOB; 40 41 void *CFAllocatorAllocateToGlob(void *unused) { 42 GLOB = CFAllocatorAllocate(NULL, 100, /*hint*/0); 43 return NULL; 44 } 45 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 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 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? 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. 77 TEST(AddressSanitizerMac, CFAllocatorMallocDoubleFree) { 78 EXPECT_DEATH(CFAllocatorMallocDoubleFree(), "attempting double-free"); 79 } 80 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). 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 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 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 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 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 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 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 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 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 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 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 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 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. 205 TEST(AddressSanitizerMac, CFStringCreateCopy) { 206 CFStringRef str = CFSTR("Hello world!\n"); 207 CFStringRef str2 = CFStringCreateCopy(0, str); 208 EXPECT_EQ(str, str2); 209 } 210 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. 219 TEST(AddressSanitizerMac, NSURLDeallocation) { 220 TestNSURLDeallocation(); 221 } 222 223 // See https://github.com/google/sanitizers/issues/109. 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