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_fuchsia.cpp
35233 views
1
//=-- lsan_common_fuchsia.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. Fuchsia-specific code.
11
//
12
//===---------------------------------------------------------------------===//
13
14
#include "lsan_common.h"
15
#include "lsan_thread.h"
16
#include "sanitizer_common/sanitizer_platform.h"
17
18
#if CAN_SANITIZE_LEAKS && SANITIZER_FUCHSIA
19
#include <zircon/sanitizer.h>
20
21
#include "lsan_allocator.h"
22
#include "sanitizer_common/sanitizer_flags.h"
23
#include "sanitizer_common/sanitizer_stoptheworld_fuchsia.h"
24
#include "sanitizer_common/sanitizer_thread_registry.h"
25
26
// Ensure that the Zircon system ABI is linked in.
27
#pragma comment(lib, "zircon")
28
29
namespace __lsan {
30
31
void InitializePlatformSpecificModules() {}
32
33
LoadedModule *GetLinker() { return nullptr; }
34
35
__attribute__((tls_model("initial-exec"))) THREADLOCAL int disable_counter;
36
bool DisabledInThisThread() { return disable_counter > 0; }
37
void DisableInThisThread() { disable_counter++; }
38
void EnableInThisThread() {
39
if (disable_counter == 0) {
40
DisableCounterUnderflow();
41
}
42
disable_counter--;
43
}
44
45
// There is nothing left to do after the globals callbacks.
46
void ProcessGlobalRegions(Frontier *frontier) {}
47
48
// Nothing to do here.
49
void ProcessPlatformSpecificAllocations(Frontier *frontier) {}
50
51
// On Fuchsia, we can intercept _Exit gracefully, and return a failing exit
52
// code if required at that point. Calling Die() here is undefined
53
// behavior and causes rare race conditions.
54
void HandleLeaks() {}
55
56
// This is defined differently in asan_fuchsia.cpp and lsan_fuchsia.cpp.
57
bool UseExitcodeOnLeak();
58
59
int ExitHook(int status) {
60
if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) {
61
if (UseExitcodeOnLeak())
62
DoLeakCheck();
63
else
64
DoRecoverableLeakCheckVoid();
65
}
66
return status == 0 && HasReportedLeaks() ? common_flags()->exitcode : status;
67
}
68
69
void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
70
CheckForLeaksParam *argument) {
71
ScopedStopTheWorldLock lock;
72
73
struct Params {
74
InternalMmapVector<uptr> allocator_caches;
75
StopTheWorldCallback callback;
76
CheckForLeaksParam *argument;
77
} params = {{}, callback, argument};
78
79
// Callback from libc for globals (data/bss modulo relro), when enabled.
80
auto globals = +[](void *chunk, size_t size, void *data) {
81
auto params = static_cast<const Params *>(data);
82
uptr begin = reinterpret_cast<uptr>(chunk);
83
uptr end = begin + size;
84
ScanGlobalRange(begin, end, &params->argument->frontier);
85
};
86
87
// Callback from libc for thread stacks.
88
auto stacks = +[](void *chunk, size_t size, void *data) {
89
auto params = static_cast<const Params *>(data);
90
uptr begin = reinterpret_cast<uptr>(chunk);
91
uptr end = begin + size;
92
ScanRangeForPointers(begin, end, &params->argument->frontier, "STACK",
93
kReachable);
94
};
95
96
// Callback from libc for thread registers.
97
auto registers = +[](void *chunk, size_t size, void *data) {
98
auto params = static_cast<const Params *>(data);
99
uptr begin = reinterpret_cast<uptr>(chunk);
100
uptr end = begin + size;
101
ScanRangeForPointers(begin, end, &params->argument->frontier, "REGISTERS",
102
kReachable);
103
};
104
105
if (flags()->use_tls) {
106
// Collect the allocator cache range from each thread so these
107
// can all be excluded from the reported TLS ranges.
108
GetAllThreadAllocatorCachesLocked(&params.allocator_caches);
109
__sanitizer::Sort(params.allocator_caches.data(),
110
params.allocator_caches.size());
111
}
112
113
// Callback from libc for TLS regions. This includes thread_local
114
// variables as well as C11 tss_set and POSIX pthread_setspecific.
115
auto tls = +[](void *chunk, size_t size, void *data) {
116
auto params = static_cast<const Params *>(data);
117
uptr begin = reinterpret_cast<uptr>(chunk);
118
uptr end = begin + size;
119
auto i = __sanitizer::InternalLowerBound(params->allocator_caches, begin);
120
if (i < params->allocator_caches.size() &&
121
params->allocator_caches[i] >= begin &&
122
params->allocator_caches[i] <= end &&
123
end - params->allocator_caches[i] >= sizeof(AllocatorCache)) {
124
// Split the range in two and omit the allocator cache within.
125
ScanRangeForPointers(begin, params->allocator_caches[i],
126
&params->argument->frontier, "TLS", kReachable);
127
uptr begin2 = params->allocator_caches[i] + sizeof(AllocatorCache);
128
ScanRangeForPointers(begin2, end, &params->argument->frontier, "TLS",
129
kReachable);
130
} else {
131
ScanRangeForPointers(begin, end, &params->argument->frontier, "TLS",
132
kReachable);
133
}
134
};
135
136
// This stops the world and then makes callbacks for various memory regions.
137
// The final callback is the last thing before the world starts up again.
138
__sanitizer_memory_snapshot(
139
flags()->use_globals ? globals : nullptr,
140
flags()->use_stacks ? stacks : nullptr,
141
flags()->use_registers ? registers : nullptr,
142
flags()->use_tls ? tls : nullptr,
143
[](zx_status_t, void *data) {
144
auto params = static_cast<const Params *>(data);
145
146
// We don't use the thread registry at all for enumerating the threads
147
// and their stacks, registers, and TLS regions. So use it separately
148
// just for the allocator cache, and to call ScanExtraStackRanges,
149
// which ASan needs.
150
if (flags()->use_stacks) {
151
InternalMmapVector<Range> ranges;
152
GetThreadExtraStackRangesLocked(&ranges);
153
ScanExtraStackRanges(ranges, &params->argument->frontier);
154
}
155
params->callback(SuspendedThreadsListFuchsia(), params->argument);
156
},
157
&params);
158
}
159
160
} // namespace __lsan
161
162
// This is declared (in extern "C") by <zircon/sanitizer.h>.
163
// _Exit calls this directly to intercept and change the status value.
164
int __sanitizer_process_exit_hook(int status) {
165
return __lsan::ExitHook(status);
166
}
167
168
#endif
169
170