Home | History | Annotate | Line # | Download | only in lsan
      1 //=-- lsan_common_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 LeakSanitizer.
     11 // Implementation of common leak checking functionality. Darwin-specific code.
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #include "sanitizer_common/sanitizer_platform.h"
     16 #include "sanitizer_common/sanitizer_libc.h"
     17 #include "lsan_common.h"
     18 
     19 #if CAN_SANITIZE_LEAKS && SANITIZER_MAC
     20 
     21 #include "sanitizer_common/sanitizer_allocator_internal.h"
     22 #include "lsan_allocator.h"
     23 
     24 #include <pthread.h>
     25 
     26 #include <mach/mach.h>
     27 
     28 // Only introduced in Mac OS X 10.9.
     29 #ifdef VM_MEMORY_OS_ALLOC_ONCE
     30 static const int kSanitizerVmMemoryOsAllocOnce = VM_MEMORY_OS_ALLOC_ONCE;
     31 #else
     32 static const int kSanitizerVmMemoryOsAllocOnce = 73;
     33 #endif
     34 
     35 namespace __lsan {
     36 
     37 typedef struct {
     38   int disable_counter;
     39   u32 current_thread_id;
     40   AllocatorCache cache;
     41 } thread_local_data_t;
     42 
     43 static pthread_key_t key;
     44 static pthread_once_t key_once = PTHREAD_ONCE_INIT;
     45 
     46 // The main thread destructor requires the current thread id,
     47 // so we can't destroy it until it's been used and reset to invalid tid
     48 void restore_tid_data(void *ptr) {
     49   thread_local_data_t *data = (thread_local_data_t *)ptr;
     50   if (data->current_thread_id != kInvalidTid)
     51     pthread_setspecific(key, data);
     52 }
     53 
     54 static void make_tls_key() {
     55   CHECK_EQ(pthread_key_create(&key, restore_tid_data), 0);
     56 }
     57 
     58 static thread_local_data_t *get_tls_val(bool alloc) {
     59   pthread_once(&key_once, make_tls_key);
     60 
     61   thread_local_data_t *ptr = (thread_local_data_t *)pthread_getspecific(key);
     62   if (ptr == NULL && alloc) {
     63     ptr = (thread_local_data_t *)InternalAlloc(sizeof(*ptr));
     64     ptr->disable_counter = 0;
     65     ptr->current_thread_id = kInvalidTid;
     66     ptr->cache = AllocatorCache();
     67     pthread_setspecific(key, ptr);
     68   }
     69 
     70   return ptr;
     71 }
     72 
     73 bool DisabledInThisThread() {
     74   thread_local_data_t *data = get_tls_val(false);
     75   return data ? data->disable_counter > 0 : false;
     76 }
     77 
     78 void DisableInThisThread() { ++get_tls_val(true)->disable_counter; }
     79 
     80 void EnableInThisThread() {
     81   int *disable_counter = &get_tls_val(true)->disable_counter;
     82   if (*disable_counter == 0) {
     83     DisableCounterUnderflow();
     84   }
     85   --*disable_counter;
     86 }
     87 
     88 u32 GetCurrentThread() {
     89   thread_local_data_t *data = get_tls_val(false);
     90   return data ? data->current_thread_id : kInvalidTid;
     91 }
     92 
     93 void SetCurrentThread(u32 tid) { get_tls_val(true)->current_thread_id = tid; }
     94 
     95 AllocatorCache *GetAllocatorCache() { return &get_tls_val(true)->cache; }
     96 
     97 LoadedModule *GetLinker() { return nullptr; }
     98 
     99 // Required on Linux for initialization of TLS behavior, but should not be
    100 // required on Darwin.
    101 void InitializePlatformSpecificModules() {}
    102 
    103 // Sections which can't contain contain global pointers. This list errs on the
    104 // side of caution to avoid false positives, at the expense of performance.
    105 //
    106 // Other potentially safe sections include:
    107 // __all_image_info, __crash_info, __const, __got, __interpose, __objc_msg_break
    108 //
    109 // Sections which definitely cannot be included here are:
    110 // __objc_data, __objc_const, __data, __bss, __common, __thread_data,
    111 // __thread_bss, __thread_vars, __objc_opt_rw, __objc_opt_ptrs
    112 static const char *kSkippedSecNames[] = {
    113     "__cfstring",       "__la_symbol_ptr",  "__mod_init_func",
    114     "__mod_term_func",  "__nl_symbol_ptr",  "__objc_classlist",
    115     "__objc_classrefs", "__objc_imageinfo", "__objc_nlclslist",
    116     "__objc_protolist", "__objc_selrefs",   "__objc_superrefs"};
    117 
    118 // Scans global variables for heap pointers.
    119 void ProcessGlobalRegions(Frontier *frontier) {
    120   for (auto name : kSkippedSecNames)
    121     CHECK(internal_strnlen(name, kMaxSegName + 1) <= kMaxSegName);
    122 
    123   MemoryMappingLayout memory_mapping(false);
    124   InternalMmapVector<LoadedModule> modules;
    125   modules.reserve(128);
    126   memory_mapping.DumpListOfModules(&modules);
    127   for (uptr i = 0; i < modules.size(); ++i) {
    128     // Even when global scanning is disabled, we still need to scan
    129     // system libraries for stashed pointers
    130     if (!flags()->use_globals && modules[i].instrumented()) continue;
    131 
    132     for (const __sanitizer::LoadedModule::AddressRange &range :
    133          modules[i].ranges()) {
    134       // Sections storing global variables are writable and non-executable
    135       if (range.executable || !range.writable) continue;
    136 
    137       for (auto name : kSkippedSecNames) {
    138         if (!internal_strcmp(range.name, name)) continue;
    139       }
    140 
    141       ScanGlobalRange(range.beg, range.end, frontier);
    142     }
    143   }
    144 }
    145 
    146 void ProcessPlatformSpecificAllocations(Frontier *frontier) {
    147   unsigned depth = 1;
    148   vm_size_t size = 0;
    149   vm_address_t address = 0;
    150   kern_return_t err = KERN_SUCCESS;
    151   mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64;
    152 
    153   InternalMmapVector<RootRegion> const *root_regions = GetRootRegions();
    154 
    155   while (err == KERN_SUCCESS) {
    156     struct vm_region_submap_info_64 info;
    157     err = vm_region_recurse_64(mach_task_self(), &address, &size, &depth,
    158                                (vm_region_info_t)&info, &count);
    159 
    160     uptr end_address = address + size;
    161 
    162     // libxpc stashes some pointers in the Kernel Alloc Once page,
    163     // make sure not to report those as leaks.
    164     if (info.user_tag == kSanitizerVmMemoryOsAllocOnce) {
    165       ScanRangeForPointers(address, end_address, frontier, "GLOBAL",
    166                            kReachable);
    167 
    168       // Recursing over the full memory map is very slow, break out
    169       // early if we don't need the full iteration.
    170       if (!flags()->use_root_regions || !root_regions->size())
    171         break;
    172     }
    173 
    174     // This additional root region scan is required on Darwin in order to
    175     // detect root regions contained within mmap'd memory regions, because
    176     // the Darwin implementation of sanitizer_procmaps traverses images
    177     // as loaded by dyld, and not the complete set of all memory regions.
    178     //
    179     // TODO(fjricci) - remove this once sanitizer_procmaps_mac has the same
    180     // behavior as sanitizer_procmaps_linux and traverses all memory regions
    181     if (flags()->use_root_regions) {
    182       for (uptr i = 0; i < root_regions->size(); i++) {
    183         ScanRootRegion(frontier, (*root_regions)[i], address, end_address,
    184                        info.protection & kProtectionRead);
    185       }
    186     }
    187 
    188     address = end_address;
    189   }
    190 }
    191 
    192 // On darwin, we can intercept _exit gracefully, and return a failing exit code
    193 // if required at that point. Calling Die() here is undefined behavior and
    194 // causes rare race conditions.
    195 void HandleLeaks() {}
    196 
    197 void DoStopTheWorld(StopTheWorldCallback callback, void *argument) {
    198   StopTheWorld(callback, argument);
    199 }
    200 
    201 } // namespace __lsan
    202 
    203 #endif // CAN_SANITIZE_LEAKS && SANITIZER_MAC
    204