Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/compiler-rt/lib/lsan/lsan_common_linux.cpp
35233 views
1
//=-- lsan_common_linux.cpp -----------------------------------------------===//
2
//
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
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This file is a part of LeakSanitizer.
10
// Implementation of common leak checking functionality. Linux/NetBSD-specific
11
// code.
12
//
13
//===----------------------------------------------------------------------===//
14
15
#include "sanitizer_common/sanitizer_platform.h"
16
#include "lsan_common.h"
17
18
#if CAN_SANITIZE_LEAKS && (SANITIZER_LINUX || SANITIZER_NETBSD)
19
#include <link.h>
20
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"
26
27
namespace __lsan {
28
29
static const char kLinkerName[] = "ld";
30
31
alignas(64) static char linker_placeholder[sizeof(LoadedModule)];
32
static LoadedModule *linker = nullptr;
33
34
static bool IsLinker(const LoadedModule& module) {
35
#if SANITIZER_USE_GETAUXVAL
36
return module.base_address() == getauxval(AT_BASE);
37
#else
38
return LibraryNameIs(module.full_name(), kLinkerName);
39
#endif // SANITIZER_USE_GETAUXVAL
40
}
41
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();
49
}
50
disable_counter--;
51
}
52
53
void InitializePlatformSpecificModules() {
54
ListOfModules modules;
55
modules.init();
56
for (LoadedModule &module : modules) {
57
if (!IsLinker(module))
58
continue;
59
if (linker == nullptr) {
60
linker = reinterpret_cast<LoadedModule *>(linker_placeholder);
61
*linker = module;
62
module = LoadedModule();
63
} else {
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);
67
linker->clear();
68
linker = nullptr;
69
return;
70
}
71
}
72
if (linker == nullptr) {
73
VReport(1, "LeakSanitizer: Dynamic linker not found. TLS and other "
74
"allocations originating from linker might be falsely reported "
75
"as leaks.\n");
76
}
77
}
78
79
static int ProcessGlobalRegionsCallback(struct dl_phdr_info *info, size_t size,
80
void *data) {
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,
85
// loadable segments.
86
if (!(phdr->p_flags & PF_W) || (phdr->p_type != PT_LOAD) ||
87
(phdr->p_memsz == 0))
88
continue;
89
uptr begin = info->dlpi_addr + phdr->p_vaddr;
90
uptr end = begin + phdr->p_memsz;
91
ScanGlobalRange(begin, end, frontier);
92
}
93
return 0;
94
}
95
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 *);
99
#endif
100
101
// Scans global variables for heap pointers.
102
void ProcessGlobalRegions(Frontier *frontier) {
103
if (!flags()->use_globals) return;
104
dl_iterate_phdr(ProcessGlobalRegionsCallback, frontier);
105
}
106
107
LoadedModule *GetLinker() { return linker; }
108
109
void ProcessPlatformSpecificAllocations(Frontier *frontier) {}
110
111
struct DoStopTheWorldParam {
112
StopTheWorldCallback callback;
113
void *argument;
114
};
115
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.
119
void HandleLeaks() {
120
if (common_flags()->exitcode) Die();
121
}
122
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);
128
return 1;
129
}
130
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, &param);
143
}
144
145
} // namespace __lsan
146
147
#endif
148
149