13cab2bb3Spatrick //=-- lsan_common_linux.cpp -----------------------------------------------===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // This file is a part of LeakSanitizer.
103cab2bb3Spatrick // Implementation of common leak checking functionality. Linux/NetBSD-specific
113cab2bb3Spatrick // code.
123cab2bb3Spatrick //
133cab2bb3Spatrick //===----------------------------------------------------------------------===//
143cab2bb3Spatrick
153cab2bb3Spatrick #include "sanitizer_common/sanitizer_platform.h"
163cab2bb3Spatrick #include "lsan_common.h"
173cab2bb3Spatrick
183cab2bb3Spatrick #if CAN_SANITIZE_LEAKS && (SANITIZER_LINUX || SANITIZER_NETBSD)
193cab2bb3Spatrick #include <link.h>
203cab2bb3Spatrick
213cab2bb3Spatrick #include "sanitizer_common/sanitizer_common.h"
223cab2bb3Spatrick #include "sanitizer_common/sanitizer_flags.h"
233cab2bb3Spatrick #include "sanitizer_common/sanitizer_getauxval.h"
243cab2bb3Spatrick #include "sanitizer_common/sanitizer_linux.h"
253cab2bb3Spatrick #include "sanitizer_common/sanitizer_stackdepot.h"
263cab2bb3Spatrick
273cab2bb3Spatrick namespace __lsan {
283cab2bb3Spatrick
293cab2bb3Spatrick static const char kLinkerName[] = "ld";
303cab2bb3Spatrick
313cab2bb3Spatrick static char linker_placeholder[sizeof(LoadedModule)] ALIGNED(64);
323cab2bb3Spatrick static LoadedModule *linker = nullptr;
333cab2bb3Spatrick
IsLinker(const LoadedModule & module)343cab2bb3Spatrick static bool IsLinker(const LoadedModule& module) {
353cab2bb3Spatrick #if SANITIZER_USE_GETAUXVAL
363cab2bb3Spatrick return module.base_address() == getauxval(AT_BASE);
373cab2bb3Spatrick #else
383cab2bb3Spatrick return LibraryNameIs(module.full_name(), kLinkerName);
393cab2bb3Spatrick #endif // SANITIZER_USE_GETAUXVAL
403cab2bb3Spatrick }
413cab2bb3Spatrick
423cab2bb3Spatrick __attribute__((tls_model("initial-exec")))
433cab2bb3Spatrick THREADLOCAL int disable_counter;
DisabledInThisThread()443cab2bb3Spatrick bool DisabledInThisThread() { return disable_counter > 0; }
DisableInThisThread()453cab2bb3Spatrick void DisableInThisThread() { disable_counter++; }
EnableInThisThread()463cab2bb3Spatrick void EnableInThisThread() {
473cab2bb3Spatrick if (disable_counter == 0) {
483cab2bb3Spatrick DisableCounterUnderflow();
493cab2bb3Spatrick }
503cab2bb3Spatrick disable_counter--;
513cab2bb3Spatrick }
523cab2bb3Spatrick
InitializePlatformSpecificModules()533cab2bb3Spatrick void InitializePlatformSpecificModules() {
543cab2bb3Spatrick ListOfModules modules;
553cab2bb3Spatrick modules.init();
563cab2bb3Spatrick for (LoadedModule &module : modules) {
573cab2bb3Spatrick if (!IsLinker(module))
583cab2bb3Spatrick continue;
593cab2bb3Spatrick if (linker == nullptr) {
603cab2bb3Spatrick linker = reinterpret_cast<LoadedModule *>(linker_placeholder);
613cab2bb3Spatrick *linker = module;
623cab2bb3Spatrick module = LoadedModule();
633cab2bb3Spatrick } else {
643cab2bb3Spatrick VReport(1, "LeakSanitizer: Multiple modules match \"%s\". "
653cab2bb3Spatrick "TLS and other allocations originating from linker might be "
663cab2bb3Spatrick "falsely reported as leaks.\n", kLinkerName);
673cab2bb3Spatrick linker->clear();
683cab2bb3Spatrick linker = nullptr;
693cab2bb3Spatrick return;
703cab2bb3Spatrick }
713cab2bb3Spatrick }
723cab2bb3Spatrick if (linker == nullptr) {
733cab2bb3Spatrick VReport(1, "LeakSanitizer: Dynamic linker not found. TLS and other "
743cab2bb3Spatrick "allocations originating from linker might be falsely reported "
753cab2bb3Spatrick "as leaks.\n");
763cab2bb3Spatrick }
773cab2bb3Spatrick }
783cab2bb3Spatrick
ProcessGlobalRegionsCallback(struct dl_phdr_info * info,size_t size,void * data)793cab2bb3Spatrick static int ProcessGlobalRegionsCallback(struct dl_phdr_info *info, size_t size,
803cab2bb3Spatrick void *data) {
813cab2bb3Spatrick Frontier *frontier = reinterpret_cast<Frontier *>(data);
823cab2bb3Spatrick for (uptr j = 0; j < info->dlpi_phnum; j++) {
833cab2bb3Spatrick const ElfW(Phdr) *phdr = &(info->dlpi_phdr[j]);
843cab2bb3Spatrick // We're looking for .data and .bss sections, which reside in writeable,
853cab2bb3Spatrick // loadable segments.
863cab2bb3Spatrick if (!(phdr->p_flags & PF_W) || (phdr->p_type != PT_LOAD) ||
873cab2bb3Spatrick (phdr->p_memsz == 0))
883cab2bb3Spatrick continue;
893cab2bb3Spatrick uptr begin = info->dlpi_addr + phdr->p_vaddr;
903cab2bb3Spatrick uptr end = begin + phdr->p_memsz;
913cab2bb3Spatrick ScanGlobalRange(begin, end, frontier);
923cab2bb3Spatrick }
933cab2bb3Spatrick return 0;
943cab2bb3Spatrick }
953cab2bb3Spatrick
96d89ec533Spatrick #if SANITIZER_ANDROID && __ANDROID_API__ < 21
97d89ec533Spatrick extern "C" __attribute__((weak)) int dl_iterate_phdr(
98d89ec533Spatrick int (*)(struct dl_phdr_info *, size_t, void *), void *);
99d89ec533Spatrick #endif
100d89ec533Spatrick
1013cab2bb3Spatrick // Scans global variables for heap pointers.
ProcessGlobalRegions(Frontier * frontier)1023cab2bb3Spatrick void ProcessGlobalRegions(Frontier *frontier) {
1033cab2bb3Spatrick if (!flags()->use_globals) return;
1043cab2bb3Spatrick dl_iterate_phdr(ProcessGlobalRegionsCallback, frontier);
1053cab2bb3Spatrick }
1063cab2bb3Spatrick
GetLinker()1073cab2bb3Spatrick LoadedModule *GetLinker() { return linker; }
1083cab2bb3Spatrick
ProcessPlatformSpecificAllocations(Frontier * frontier)1093cab2bb3Spatrick void ProcessPlatformSpecificAllocations(Frontier *frontier) {}
1103cab2bb3Spatrick
1113cab2bb3Spatrick struct DoStopTheWorldParam {
1123cab2bb3Spatrick StopTheWorldCallback callback;
1133cab2bb3Spatrick void *argument;
1143cab2bb3Spatrick };
1153cab2bb3Spatrick
1163cab2bb3Spatrick // While calling Die() here is undefined behavior and can potentially
1173cab2bb3Spatrick // cause race conditions, it isn't possible to intercept exit on linux,
1183cab2bb3Spatrick // so we have no choice but to call Die() from the atexit handler.
HandleLeaks()1193cab2bb3Spatrick void HandleLeaks() {
1203cab2bb3Spatrick if (common_flags()->exitcode) Die();
1213cab2bb3Spatrick }
1223cab2bb3Spatrick
LockStuffAndStopTheWorldCallback(struct dl_phdr_info * info,size_t size,void * data)1233cab2bb3Spatrick static int LockStuffAndStopTheWorldCallback(struct dl_phdr_info *info,
1243cab2bb3Spatrick size_t size, void *data) {
125*810390e3Srobert ScopedStopTheWorldLock lock;
1263cab2bb3Spatrick DoStopTheWorldParam *param = reinterpret_cast<DoStopTheWorldParam *>(data);
1273cab2bb3Spatrick StopTheWorld(param->callback, param->argument);
1283cab2bb3Spatrick return 1;
1293cab2bb3Spatrick }
1303cab2bb3Spatrick
1313cab2bb3Spatrick // LSan calls dl_iterate_phdr() from the tracer task. This may deadlock: if one
1323cab2bb3Spatrick // of the threads is frozen while holding the libdl lock, the tracer will hang
1333cab2bb3Spatrick // in dl_iterate_phdr() forever.
1343cab2bb3Spatrick // Luckily, (a) the lock is reentrant and (b) libc can't distinguish between the
1353cab2bb3Spatrick // tracer task and the thread that spawned it. Thus, if we run the tracer task
1363cab2bb3Spatrick // while holding the libdl lock in the parent thread, we can safely reenter it
1373cab2bb3Spatrick // in the tracer. The solution is to run stoptheworld from a dl_iterate_phdr()
1383cab2bb3Spatrick // callback in the parent thread.
LockStuffAndStopTheWorld(StopTheWorldCallback callback,CheckForLeaksParam * argument)1391f9cb04fSpatrick void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
1401f9cb04fSpatrick CheckForLeaksParam *argument) {
1413cab2bb3Spatrick DoStopTheWorldParam param = {callback, argument};
1423cab2bb3Spatrick dl_iterate_phdr(LockStuffAndStopTheWorldCallback, ¶m);
1433cab2bb3Spatrick }
1443cab2bb3Spatrick
1453cab2bb3Spatrick } // namespace __lsan
1463cab2bb3Spatrick
1473cab2bb3Spatrick #endif
148