brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.4 KiB · 4b21f12 Raw
242 lines · cpp
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-exception6//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 21TEST(AddressSanitizerMac, CFAllocatorDefaultDoubleFree) {22  EXPECT_DEATH(23      CFAllocatorDefaultDoubleFree(NULL),24      "attempting double-free");25}26 27void CFAllocator_DoubleFreeOnPthread() {28  pthread_t child;29  PTHREAD_CREATE(&child, NULL, CFAllocatorDefaultDoubleFree, NULL);30  PTHREAD_JOIN(child, NULL);  // Shouldn't be reached.31}32 33TEST(AddressSanitizerMac, CFAllocatorDefaultDoubleFree_ChildPhread) {34  EXPECT_DEATH(CFAllocator_DoubleFreeOnPthread(), "attempting double-free");35}36 37namespace {38 39void *GLOB;40 41void *CFAllocatorAllocateToGlob(void *unused) {42  GLOB = CFAllocatorAllocate(NULL, 100, /*hint*/0);43  return NULL;44}45 46void *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 53void 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 61TEST(AddressSanitizerMac, CFAllocator_PassMemoryToAnotherThread) {62  EXPECT_DEATH(CFAllocator_PassMemoryToAnotherThread(),63               "heap-buffer-overflow");64}65 66}  // namespace67 68// TODO(glider): figure out whether we still need these tests. Is it correct69// to intercept the non-default CFAllocators?70TEST(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.77TEST(AddressSanitizerMac, CFAllocatorMallocDoubleFree) {78  EXPECT_DEATH(CFAllocatorMallocDoubleFree(), "attempting double-free");79}80 81TEST(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 byte86// legend, i.e. managed to print the thread stacks (this almost certainly87// means that the libdispatch task creation has been intercepted correctly).88TEST(AddressSanitizerMac, GCDDispatchAsync) {89  // Make sure the whole ASan report is printed, i.e. that we don't die90  // on a CHECK.91  EXPECT_DEATH(TestGCDDispatchAsync(), "Shadow byte legend");92}93 94TEST(AddressSanitizerMac, GCDDispatchSync) {95  // Make sure the whole ASan report is printed, i.e. that we don't die96  // on a CHECK.97  EXPECT_DEATH(TestGCDDispatchSync(), "Shadow byte legend");98}99 100 101TEST(AddressSanitizerMac, GCDReuseWqthreadsAsync) {102  // Make sure the whole ASan report is printed, i.e. that we don't die103  // on a CHECK.104  EXPECT_DEATH(TestGCDReuseWqthreadsAsync(), "Shadow byte legend");105}106 107TEST(AddressSanitizerMac, GCDReuseWqthreadsSync) {108  // Make sure the whole ASan report is printed, i.e. that we don't die109  // on a CHECK.110  EXPECT_DEATH(TestGCDReuseWqthreadsSync(), "Shadow byte legend");111}112 113TEST(AddressSanitizerMac, GCDDispatchAfter) {114  // Make sure the whole ASan report is printed, i.e. that we don't die115  // on a CHECK.116  EXPECT_DEATH(TestGCDDispatchAfter(), "Shadow byte legend");117}118 119TEST(AddressSanitizerMac, GCDDispatchApply) {120  // Make sure the whole ASan report is printed, i.e. that we don't die121  // on a CHECK.122  EXPECT_DEATH(TestGCDDispatchApply(), "Shadow byte legend");123}124 125TEST(AddressSanitizerMac, GCDSourceEvent) {126  // Make sure the whole ASan report is printed, i.e. that we don't die127  // on a CHECK.128  EXPECT_DEATH(TestGCDSourceEvent(), "Shadow byte legend");129}130 131TEST(AddressSanitizerMac, GCDSourceCancel) {132  // Make sure the whole ASan report is printed, i.e. that we don't die133  // on a CHECK.134  EXPECT_DEATH(TestGCDSourceCancel(), "Shadow byte legend");135}136 137TEST(AddressSanitizerMac, GCDGroupAsync) {138  // Make sure the whole ASan report is printed, i.e. that we don't die139  // on a CHECK.140  EXPECT_DEATH(TestGCDGroupAsync(), "Shadow byte legend");141}142 143void *MallocIntrospectionLockWorker(void *_) {144  const int kNumPointers = 100;145  int i;146  void *pointers[kNumPointers];147  for (i = 0; i < kNumPointers; i++) {148    pointers[i] = malloc(i + 1);149  }150  for (i = 0; i < kNumPointers; i++) {151    free(pointers[i]);152  }153 154  return NULL;155}156 157void *MallocIntrospectionLockForker(void *_) {158  pid_t result = fork();159  if (result == -1) {160    perror("fork");161  }162  assert(result != -1);163  if (result == 0) {164    // Call malloc in the child process to make sure we won't deadlock.165    void *ptr = malloc(42);166    free(ptr);167    exit(0);168  } else {169    // Return in the parent process.170    return NULL;171  }172}173 174TEST(AddressSanitizerMac, MallocIntrospectionLock) {175  // Incorrect implementation of force_lock and force_unlock in our malloc zone176  // will cause forked processes to deadlock.177  // TODO(glider): need to detect that none of the child processes deadlocked.178  const int kNumWorkers = 5, kNumIterations = 100;179  int i, iter;180  for (iter = 0; iter < kNumIterations; iter++) {181    pthread_t workers[kNumWorkers], forker;182    for (i = 0; i < kNumWorkers; i++) {183      PTHREAD_CREATE(&workers[i], 0, MallocIntrospectionLockWorker, 0);184    }185    PTHREAD_CREATE(&forker, 0, MallocIntrospectionLockForker, 0);186    for (i = 0; i < kNumWorkers; i++) {187      PTHREAD_JOIN(workers[i], 0);188    }189    PTHREAD_JOIN(forker, 0);190  }191}192 193void *TSDAllocWorker(void *test_key) {194  if (test_key) {195    void *mem = malloc(10);196    pthread_setspecific(*(pthread_key_t*)test_key, mem);197  }198  return NULL;199}200 201TEST(AddressSanitizerMac, DISABLED_TSDWorkqueueTest) {202  pthread_t th;203  pthread_key_t test_key;204  pthread_key_create(&test_key, CallFreeOnWorkqueue);205  PTHREAD_CREATE(&th, NULL, TSDAllocWorker, &test_key);206  PTHREAD_JOIN(th, NULL);207  pthread_key_delete(test_key);208}209 210// Test that CFStringCreateCopy does not copy constant strings.211TEST(AddressSanitizerMac, CFStringCreateCopy) {212  CFStringRef str = CFSTR("Hello world!\n");213  CFStringRef str2 = CFStringCreateCopy(0, str);214  EXPECT_EQ(str, str2);215}216 217TEST(AddressSanitizerMac, NSObjectOOB) {218  // Make sure that our allocators are used for NSObjects.219  EXPECT_DEATH(TestOOBNSObjects(), "heap-buffer-overflow");220}221 222// Make sure that correct pointer is passed to free() when deallocating a223// NSURL object.224// See https://github.com/google/sanitizers/issues/70.225TEST(AddressSanitizerMac, NSURLDeallocation) {226  TestNSURLDeallocation();227}228 229// See https://github.com/google/sanitizers/issues/109.230TEST(AddressSanitizerMac, Mstats) {231  malloc_statistics_t stats1, stats2;232  malloc_zone_statistics(/*all zones*/NULL, &stats1);233  const size_t kMallocSize = 100000;234  void *alloc = Ident(malloc(kMallocSize));235  malloc_zone_statistics(/*all zones*/NULL, &stats2);236  EXPECT_GT(stats2.blocks_in_use, stats1.blocks_in_use);237  EXPECT_GE(stats2.size_in_use - stats1.size_in_use, kMallocSize);238  free(alloc);239  // Even the default OSX allocator may not change the stats after free().240}241 242