Home | History | Annotate | Line # | Download | only in lsan
      1 //=-- lsan_common_linux.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 LeakSanitizer.
     10 // Implementation of common leak checking functionality. Linux/NetBSD-specific
     11 // code.
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #include "sanitizer_common/sanitizer_platform.h"
     16 #include "lsan_common.h"
     17 
     18 #if CAN_SANITIZE_LEAKS && (SANITIZER_LINUX || SANITIZER_NETBSD)
     19 #include <link.h>
     20 
     21 #include "sanitizer_common/sanitizer_common.h"
     22 #include "sanitizer_common/sanitizer_flags.h"
     23 #include "sanitizer_common/sanitizer_getauxval.h"
     24 #include "sanitizer_common/sanitizer_linux.h"
     25 #include "sanitizer_common/sanitizer_stackdepot.h"
     26 
     27 namespace __lsan {
     28 
     29 static const char kLinkerName[] = "ld";
     30 
     31 static char linker_placeholder[sizeof(LoadedModule)] ALIGNED(64);
     32 static LoadedModule *linker = nullptr;
     33 
     34 static bool IsLinker(const LoadedModule& module) {
     35 #if SANITIZER_USE_GETAUXVAL
     36   return module.base_address() == getauxval(AT_BASE);
     37 #else
     38   return LibraryNameIs(module.full_name(), kLinkerName);
     39 #endif  // SANITIZER_USE_GETAUXVAL
     40 }
     41 
     42 __attribute__((tls_model("initial-exec")))
     43 THREADLOCAL int disable_counter;
     44 bool DisabledInThisThread() { return disable_counter > 0; }
     45 void DisableInThisThread() { disable_counter++; }
     46 void EnableInThisThread() {
     47   if (disable_counter == 0) {
     48     DisableCounterUnderflow();
     49   }
     50   disable_counter--;
     51 }
     52 
     53 void InitializePlatformSpecificModules() {
     54   ListOfModules modules;
     55   modules.init();
     56   for (LoadedModule &module : modules) {
     57     if (!IsLinker(module))
     58       continue;
     59     if (linker == nullptr) {
     60       linker = reinterpret_cast<LoadedModule *>(linker_placeholder);
     61       *linker = module;
     62       module = LoadedModule();
     63     } else {
     64       VReport(1, "LeakSanitizer: Multiple modules match \"%s\". "
     65               "TLS and other allocations originating from linker might be "
     66               "falsely reported as leaks.\n", kLinkerName);
     67       linker->clear();
     68       linker = nullptr;
     69       return;
     70     }
     71   }
     72   if (linker == nullptr) {
     73     VReport(1, "LeakSanitizer: Dynamic linker not found. TLS and other "
     74                "allocations originating from linker might be falsely reported "
     75                 "as leaks.\n");
     76   }
     77 }
     78 
     79 static int ProcessGlobalRegionsCallback(struct dl_phdr_info *info, size_t size,
     80                                         void *data) {
     81   Frontier *frontier = reinterpret_cast<Frontier *>(data);
     82   for (uptr j = 0; j < info->dlpi_phnum; j++) {
     83     const ElfW(Phdr) *phdr = &(info->dlpi_phdr[j]);
     84     // We're looking for .data and .bss sections, which reside in writeable,
     85     // loadable segments.
     86     if (!(phdr->p_flags & PF_W) || (phdr->p_type != PT_LOAD) ||
     87         (phdr->p_memsz == 0))
     88       continue;
     89     uptr begin = info->dlpi_addr + phdr->p_vaddr;
     90     uptr end = begin + phdr->p_memsz;
     91     ScanGlobalRange(begin, end, frontier);
     92   }
     93   return 0;
     94 }
     95 
     96 #if SANITIZER_ANDROID && __ANDROID_API__ < 21
     97 extern "C" __attribute__((weak)) int dl_iterate_phdr(
     98     int (*)(struct dl_phdr_info *, size_t, void *), void *);
     99 #endif
    100 
    101 // Scans global variables for heap pointers.
    102 void ProcessGlobalRegions(Frontier *frontier) {
    103   if (!flags()->use_globals) return;
    104   dl_iterate_phdr(ProcessGlobalRegionsCallback, frontier);
    105 }
    106 
    107 LoadedModule *GetLinker() { return linker; }
    108 
    109 void ProcessPlatformSpecificAllocations(Frontier *frontier) {}
    110 
    111 struct DoStopTheWorldParam {
    112   StopTheWorldCallback callback;
    113   void *argument;
    114 };
    115 
    116 // While calling Die() here is undefined behavior and can potentially
    117 // cause race conditions, it isn't possible to intercept exit on linux,
    118 // so we have no choice but to call Die() from the atexit handler.
    119 void HandleLeaks() {
    120   if (common_flags()->exitcode) Die();
    121 }
    122 
    123 static int LockStuffAndStopTheWorldCallback(struct dl_phdr_info *info,
    124                                             size_t size, void *data) {
    125   LockThreadRegistry();
    126   LockAllocator();
    127   DoStopTheWorldParam *param = reinterpret_cast<DoStopTheWorldParam *>(data);
    128   StopTheWorld(param->callback, param->argument);
    129   UnlockAllocator();
    130   UnlockThreadRegistry();
    131   return 1;
    132 }
    133 
    134 // LSan calls dl_iterate_phdr() from the tracer task. This may deadlock: if one
    135 // of the threads is frozen while holding the libdl lock, the tracer will hang
    136 // in dl_iterate_phdr() forever.
    137 // Luckily, (a) the lock is reentrant and (b) libc can't distinguish between the
    138 // tracer task and the thread that spawned it. Thus, if we run the tracer task
    139 // while holding the libdl lock in the parent thread, we can safely reenter it
    140 // in the tracer. The solution is to run stoptheworld from a dl_iterate_phdr()
    141 // callback in the parent thread.
    142 void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
    143                               CheckForLeaksParam *argument) {
    144   DoStopTheWorldParam param = {callback, argument};
    145   dl_iterate_phdr(LockStuffAndStopTheWorldCallback, &param);
    146 }
    147 
    148 } // namespace __lsan
    149 
    150 #endif
    151