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