xref: /openbsd-src/gnu/llvm/compiler-rt/lib/lsan/lsan_common_linux.cpp (revision 810390e339a5425391477d5d41c78d7cab2424ac)
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, &param);
1433cab2bb3Spatrick }
1443cab2bb3Spatrick 
1453cab2bb3Spatrick } // namespace __lsan
1463cab2bb3Spatrick 
1473cab2bb3Spatrick #endif
148