1 //=-- lsan_common_linux.cpp -----------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file is a part of LeakSanitizer.
10 // Implementation of common leak checking functionality. Linux/NetBSD-specific
13 //===----------------------------------------------------------------------===//
15 #include "sanitizer_common/sanitizer_platform.h"
16 #include "lsan_common.h"
18 #if CAN_SANITIZE_LEAKS && (SANITIZER_LINUX || SANITIZER_NETBSD)
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"
29 static const char kLinkerName
[] = "ld";
31 alignas(64) static char linker_placeholder
[sizeof(LoadedModule
)];
32 static LoadedModule
*linker
= nullptr;
34 static bool IsLinker(const LoadedModule
& module
) {
35 #if SANITIZER_USE_GETAUXVAL
36 return module
.base_address() == getauxval(AT_BASE
);
38 return LibraryNameIs(module
.full_name(), kLinkerName
);
39 #endif // SANITIZER_USE_GETAUXVAL
42 __attribute__((tls_model("initial-exec")))
43 THREADLOCAL
int disable_counter
;
44 bool DisabledInThisThread() { return disable_counter
> 0; }
45 void DisableInThisThread() { disable_counter
++; }
46 void EnableInThisThread() {
47 if (disable_counter
== 0) {
48 DisableCounterUnderflow();
53 void InitializePlatformSpecificModules() {
54 ListOfModules modules
;
56 for (LoadedModule
&module
: modules
) {
57 if (!IsLinker(module
))
59 if (linker
== nullptr) {
60 linker
= reinterpret_cast<LoadedModule
*>(linker_placeholder
);
62 module
= LoadedModule();
64 VReport(1, "LeakSanitizer: Multiple modules match \"%s\". "
65 "TLS and other allocations originating from linker might be "
66 "falsely reported as leaks.\n", kLinkerName
);
72 if (linker
== nullptr) {
73 VReport(1, "LeakSanitizer: Dynamic linker not found. TLS and other "
74 "allocations originating from linker might be falsely reported "
79 static int ProcessGlobalRegionsCallback(struct dl_phdr_info
*info
, size_t size
,
81 Frontier
*frontier
= reinterpret_cast<Frontier
*>(data
);
82 for (uptr j
= 0; j
< info
->dlpi_phnum
; j
++) {
83 const ElfW(Phdr
) *phdr
= &(info
->dlpi_phdr
[j
]);
84 // We're looking for .data and .bss sections, which reside in writeable,
86 if (!(phdr
->p_flags
& PF_W
) || (phdr
->p_type
!= PT_LOAD
) ||
89 uptr begin
= info
->dlpi_addr
+ phdr
->p_vaddr
;
90 uptr end
= begin
+ phdr
->p_memsz
;
91 ScanGlobalRange(begin
, end
, frontier
);
96 #if SANITIZER_ANDROID && __ANDROID_API__ < 21
97 extern "C" __attribute__((weak
)) int dl_iterate_phdr(
98 int (*)(struct dl_phdr_info
*, size_t, void *), void *);
101 // Scans global variables for heap pointers.
102 void ProcessGlobalRegions(Frontier
*frontier
) {
103 if (!flags()->use_globals
) return;
104 dl_iterate_phdr(ProcessGlobalRegionsCallback
, frontier
);
107 LoadedModule
*GetLinker() { return linker
; }
109 void ProcessPlatformSpecificAllocations(Frontier
*frontier
) {}
111 struct DoStopTheWorldParam
{
112 StopTheWorldCallback callback
;
116 // While calling Die() here is undefined behavior and can potentially
117 // cause race conditions, it isn't possible to intercept exit on linux,
118 // so we have no choice but to call Die() from the atexit handler.
120 if (common_flags()->exitcode
) Die();
123 static int LockStuffAndStopTheWorldCallback(struct dl_phdr_info
*info
,
124 size_t size
, void *data
) {
125 ScopedStopTheWorldLock lock
;
126 DoStopTheWorldParam
*param
= reinterpret_cast<DoStopTheWorldParam
*>(data
);
127 StopTheWorld(param
->callback
, param
->argument
);
131 // LSan calls dl_iterate_phdr() from the tracer task. This may deadlock: if one
132 // of the threads is frozen while holding the libdl lock, the tracer will hang
133 // in dl_iterate_phdr() forever.
134 // Luckily, (a) the lock is reentrant and (b) libc can't distinguish between the
135 // tracer task and the thread that spawned it. Thus, if we run the tracer task
136 // while holding the libdl lock in the parent thread, we can safely reenter it
137 // in the tracer. The solution is to run stoptheworld from a dl_iterate_phdr()
138 // callback in the parent thread.
139 void LockStuffAndStopTheWorld(StopTheWorldCallback callback
,
140 CheckForLeaksParam
*argument
) {
141 DoStopTheWorldParam param
= {callback
, argument
};
142 dl_iterate_phdr(LockStuffAndStopTheWorldCallback
, ¶m
);
145 } // namespace __lsan