168d75effSDimitry Andric //=-- lsan_common_linux.cpp -----------------------------------------------===// 268d75effSDimitry Andric // 368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 668d75effSDimitry Andric // 768d75effSDimitry Andric //===----------------------------------------------------------------------===// 868d75effSDimitry Andric // 968d75effSDimitry Andric // This file is a part of LeakSanitizer. 1068d75effSDimitry Andric // Implementation of common leak checking functionality. Linux/NetBSD-specific 1168d75effSDimitry Andric // code. 1268d75effSDimitry Andric // 1368d75effSDimitry Andric //===----------------------------------------------------------------------===// 1468d75effSDimitry Andric 1568d75effSDimitry Andric #include "sanitizer_common/sanitizer_platform.h" 1668d75effSDimitry Andric #include "lsan_common.h" 1768d75effSDimitry Andric 1868d75effSDimitry Andric #if CAN_SANITIZE_LEAKS && (SANITIZER_LINUX || SANITIZER_NETBSD) 1968d75effSDimitry Andric #include <link.h> 2068d75effSDimitry Andric 2168d75effSDimitry Andric #include "sanitizer_common/sanitizer_common.h" 2268d75effSDimitry Andric #include "sanitizer_common/sanitizer_flags.h" 2368d75effSDimitry Andric #include "sanitizer_common/sanitizer_getauxval.h" 2468d75effSDimitry Andric #include "sanitizer_common/sanitizer_linux.h" 2568d75effSDimitry Andric #include "sanitizer_common/sanitizer_stackdepot.h" 2668d75effSDimitry Andric 2768d75effSDimitry Andric namespace __lsan { 2868d75effSDimitry Andric 2968d75effSDimitry Andric static const char kLinkerName[] = "ld"; 3068d75effSDimitry Andric 31*0fca6ea1SDimitry Andric alignas(64) static char linker_placeholder[sizeof(LoadedModule)]; 3268d75effSDimitry Andric static LoadedModule *linker = nullptr; 3368d75effSDimitry Andric 3468d75effSDimitry Andric static bool IsLinker(const LoadedModule& module) { 3568d75effSDimitry Andric #if SANITIZER_USE_GETAUXVAL 3668d75effSDimitry Andric return module.base_address() == getauxval(AT_BASE); 3768d75effSDimitry Andric #else 3868d75effSDimitry Andric return LibraryNameIs(module.full_name(), kLinkerName); 3968d75effSDimitry Andric #endif // SANITIZER_USE_GETAUXVAL 4068d75effSDimitry Andric } 4168d75effSDimitry Andric 4268d75effSDimitry Andric __attribute__((tls_model("initial-exec"))) 4368d75effSDimitry Andric THREADLOCAL int disable_counter; 4468d75effSDimitry Andric bool DisabledInThisThread() { return disable_counter > 0; } 4568d75effSDimitry Andric void DisableInThisThread() { disable_counter++; } 4668d75effSDimitry Andric void EnableInThisThread() { 4768d75effSDimitry Andric if (disable_counter == 0) { 4868d75effSDimitry Andric DisableCounterUnderflow(); 4968d75effSDimitry Andric } 5068d75effSDimitry Andric disable_counter--; 5168d75effSDimitry Andric } 5268d75effSDimitry Andric 5368d75effSDimitry Andric void InitializePlatformSpecificModules() { 5468d75effSDimitry Andric ListOfModules modules; 5568d75effSDimitry Andric modules.init(); 5668d75effSDimitry Andric for (LoadedModule &module : modules) { 5768d75effSDimitry Andric if (!IsLinker(module)) 5868d75effSDimitry Andric continue; 5968d75effSDimitry Andric if (linker == nullptr) { 6068d75effSDimitry Andric linker = reinterpret_cast<LoadedModule *>(linker_placeholder); 6168d75effSDimitry Andric *linker = module; 6268d75effSDimitry Andric module = LoadedModule(); 6368d75effSDimitry Andric } else { 6468d75effSDimitry Andric VReport(1, "LeakSanitizer: Multiple modules match \"%s\". " 6568d75effSDimitry Andric "TLS and other allocations originating from linker might be " 6668d75effSDimitry Andric "falsely reported as leaks.\n", kLinkerName); 6768d75effSDimitry Andric linker->clear(); 6868d75effSDimitry Andric linker = nullptr; 6968d75effSDimitry Andric return; 7068d75effSDimitry Andric } 7168d75effSDimitry Andric } 7268d75effSDimitry Andric if (linker == nullptr) { 7368d75effSDimitry Andric VReport(1, "LeakSanitizer: Dynamic linker not found. TLS and other " 7468d75effSDimitry Andric "allocations originating from linker might be falsely reported " 7568d75effSDimitry Andric "as leaks.\n"); 7668d75effSDimitry Andric } 7768d75effSDimitry Andric } 7868d75effSDimitry Andric 7968d75effSDimitry Andric static int ProcessGlobalRegionsCallback(struct dl_phdr_info *info, size_t size, 8068d75effSDimitry Andric void *data) { 8168d75effSDimitry Andric Frontier *frontier = reinterpret_cast<Frontier *>(data); 8268d75effSDimitry Andric for (uptr j = 0; j < info->dlpi_phnum; j++) { 8368d75effSDimitry Andric const ElfW(Phdr) *phdr = &(info->dlpi_phdr[j]); 8468d75effSDimitry Andric // We're looking for .data and .bss sections, which reside in writeable, 8568d75effSDimitry Andric // loadable segments. 8668d75effSDimitry Andric if (!(phdr->p_flags & PF_W) || (phdr->p_type != PT_LOAD) || 8768d75effSDimitry Andric (phdr->p_memsz == 0)) 8868d75effSDimitry Andric continue; 8968d75effSDimitry Andric uptr begin = info->dlpi_addr + phdr->p_vaddr; 9068d75effSDimitry Andric uptr end = begin + phdr->p_memsz; 9168d75effSDimitry Andric ScanGlobalRange(begin, end, frontier); 9268d75effSDimitry Andric } 9368d75effSDimitry Andric return 0; 9468d75effSDimitry Andric } 9568d75effSDimitry Andric 96e8d8bef9SDimitry Andric #if SANITIZER_ANDROID && __ANDROID_API__ < 21 97e8d8bef9SDimitry Andric extern "C" __attribute__((weak)) int dl_iterate_phdr( 98e8d8bef9SDimitry Andric int (*)(struct dl_phdr_info *, size_t, void *), void *); 99e8d8bef9SDimitry Andric #endif 100e8d8bef9SDimitry Andric 10168d75effSDimitry Andric // Scans global variables for heap pointers. 10268d75effSDimitry Andric void ProcessGlobalRegions(Frontier *frontier) { 10368d75effSDimitry Andric if (!flags()->use_globals) return; 10468d75effSDimitry Andric dl_iterate_phdr(ProcessGlobalRegionsCallback, frontier); 10568d75effSDimitry Andric } 10668d75effSDimitry Andric 10768d75effSDimitry Andric LoadedModule *GetLinker() { return linker; } 10868d75effSDimitry Andric 10968d75effSDimitry Andric void ProcessPlatformSpecificAllocations(Frontier *frontier) {} 11068d75effSDimitry Andric 11168d75effSDimitry Andric struct DoStopTheWorldParam { 11268d75effSDimitry Andric StopTheWorldCallback callback; 11368d75effSDimitry Andric void *argument; 11468d75effSDimitry Andric }; 11568d75effSDimitry Andric 11668d75effSDimitry Andric // While calling Die() here is undefined behavior and can potentially 11768d75effSDimitry Andric // cause race conditions, it isn't possible to intercept exit on linux, 11868d75effSDimitry Andric // so we have no choice but to call Die() from the atexit handler. 11968d75effSDimitry Andric void HandleLeaks() { 12068d75effSDimitry Andric if (common_flags()->exitcode) Die(); 12168d75effSDimitry Andric } 12268d75effSDimitry Andric 12368d75effSDimitry Andric static int LockStuffAndStopTheWorldCallback(struct dl_phdr_info *info, 12468d75effSDimitry Andric size_t size, void *data) { 1250eae32dcSDimitry Andric ScopedStopTheWorldLock lock; 12668d75effSDimitry Andric DoStopTheWorldParam *param = reinterpret_cast<DoStopTheWorldParam *>(data); 12768d75effSDimitry Andric StopTheWorld(param->callback, param->argument); 12868d75effSDimitry Andric return 1; 12968d75effSDimitry Andric } 13068d75effSDimitry Andric 13168d75effSDimitry Andric // LSan calls dl_iterate_phdr() from the tracer task. This may deadlock: if one 13268d75effSDimitry Andric // of the threads is frozen while holding the libdl lock, the tracer will hang 13368d75effSDimitry Andric // in dl_iterate_phdr() forever. 13468d75effSDimitry Andric // Luckily, (a) the lock is reentrant and (b) libc can't distinguish between the 13568d75effSDimitry Andric // tracer task and the thread that spawned it. Thus, if we run the tracer task 13668d75effSDimitry Andric // while holding the libdl lock in the parent thread, we can safely reenter it 13768d75effSDimitry Andric // in the tracer. The solution is to run stoptheworld from a dl_iterate_phdr() 13868d75effSDimitry Andric // callback in the parent thread. 1395ffd83dbSDimitry Andric void LockStuffAndStopTheWorld(StopTheWorldCallback callback, 1405ffd83dbSDimitry Andric CheckForLeaksParam *argument) { 14168d75effSDimitry Andric DoStopTheWorldParam param = {callback, argument}; 14268d75effSDimitry Andric dl_iterate_phdr(LockStuffAndStopTheWorldCallback, ¶m); 14368d75effSDimitry Andric } 14468d75effSDimitry Andric 14568d75effSDimitry Andric } // namespace __lsan 14668d75effSDimitry Andric 14768d75effSDimitry Andric #endif 148