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() { 45 #if SANITIZER_ANDROID 46 // LSAN is only enabled with Android-S and up. 47 if (!HAS_ANDROID_THREAD_PROPERTIES_API) 48 return true; 49 #endif 50 return disable_counter > 0; 51 } 52 void DisableInThisThread() { 53 #if SANITIZER_ANDROID 54 // LSAN is only enabled with Android-S and up. 55 if (!HAS_ANDROID_THREAD_PROPERTIES_API) 56 return; 57 #endif 58 disable_counter++; 59 } 60 void EnableInThisThread() { 61 #if SANITIZER_ANDROID 62 // LSAN is only enabled with Android-S and up. 63 if (!HAS_ANDROID_THREAD_PROPERTIES_API) 64 return; 65 #endif 66 if (disable_counter == 0) { 67 DisableCounterUnderflow(); 68 } 69 disable_counter--; 70 } 71 72 void InitializePlatformSpecificModules() { 73 ListOfModules modules; 74 modules.init(); 75 for (LoadedModule &module : modules) { 76 if (!IsLinker(module)) 77 continue; 78 if (linker == nullptr) { 79 linker = reinterpret_cast<LoadedModule *>(linker_placeholder); 80 *linker = module; 81 module = LoadedModule(); 82 } else { 83 VReport(1, "LeakSanitizer: Multiple modules match \"%s\". " 84 "TLS and other allocations originating from linker might be " 85 "falsely reported as leaks.\n", kLinkerName); 86 linker->clear(); 87 linker = nullptr; 88 return; 89 } 90 } 91 if (linker == nullptr) { 92 VReport(1, "LeakSanitizer: Dynamic linker not found. TLS and other " 93 "allocations originating from linker might be falsely reported " 94 "as leaks.\n"); 95 } 96 } 97 98 static int ProcessGlobalRegionsCallback(struct dl_phdr_info *info, size_t size, 99 void *data) { 100 Frontier *frontier = reinterpret_cast<Frontier *>(data); 101 for (uptr j = 0; j < info->dlpi_phnum; j++) { 102 const ElfW(Phdr) *phdr = &(info->dlpi_phdr[j]); 103 // We're looking for .data and .bss sections, which reside in writeable, 104 // loadable segments. 105 if (!(phdr->p_flags & PF_W) || (phdr->p_type != PT_LOAD) || 106 (phdr->p_memsz == 0)) 107 continue; 108 uptr begin = info->dlpi_addr + phdr->p_vaddr; 109 uptr end = begin + phdr->p_memsz; 110 ScanGlobalRange(begin, end, frontier); 111 } 112 return 0; 113 } 114 115 // Scans global variables for heap pointers. 116 void ProcessGlobalRegions(Frontier *frontier) { 117 if (!flags()->use_globals) { 118 #if SANITIZER_ANDROID 119 // There are known malloc'ed global variables from libc[++] on Android. 120 // If use_globals is turnt off, we could see leaks. 121 // Issue a warning in case users turn it off by accident. 122 Report("use_globals=0 on Android could lead to false reports."); 123 #endif 124 return; 125 } 126 dl_iterate_phdr(ProcessGlobalRegionsCallback, frontier); 127 } 128 129 LoadedModule *GetLinker() { return linker; } 130 131 void ProcessPlatformSpecificAllocations(Frontier *frontier) {} 132 133 struct DoStopTheWorldParam { 134 StopTheWorldCallback callback; 135 void *argument; 136 }; 137 138 // While calling Die() here is undefined behavior and can potentially 139 // cause race conditions, it isn't possible to intercept exit on linux, 140 // so we have no choice but to call Die() from the atexit handler. 141 void HandleLeaks() { 142 if (common_flags()->exitcode) Die(); 143 } 144 145 static int LockStuffAndStopTheWorldCallback(struct dl_phdr_info *info, 146 size_t size, void *data) { 147 LockThreadRegistry(); 148 LockAllocator(); 149 DoStopTheWorldParam *param = reinterpret_cast<DoStopTheWorldParam *>(data); 150 StopTheWorld(param->callback, param->argument); 151 UnlockAllocator(); 152 UnlockThreadRegistry(); 153 return 1; 154 } 155 156 // LSan calls dl_iterate_phdr() from the tracer task. This may deadlock: if one 157 // of the threads is frozen while holding the libdl lock, the tracer will hang 158 // in dl_iterate_phdr() forever. 159 // Luckily, (a) the lock is reentrant and (b) libc can't distinguish between the 160 // tracer task and the thread that spawned it. Thus, if we run the tracer task 161 // while holding the libdl lock in the parent thread, we can safely reenter it 162 // in the tracer. The solution is to run stoptheworld from a dl_iterate_phdr() 163 // callback in the parent thread. 164 void LockStuffAndStopTheWorld(StopTheWorldCallback callback, 165 CheckForLeaksParam *argument) { 166 DoStopTheWorldParam param = {callback, argument}; 167 dl_iterate_phdr(LockStuffAndStopTheWorldCallback, ¶m); 168 } 169 170 } // namespace __lsan 171 172 #endif 173