Skip to content

Commit f4c6088

Browse files
authored
[lsan] Process non-suspended threads (llvm#112807)
For such threads we have no registers, so no exact stack range, and no guaranties that stack is mapped at all. To avoid crashes on unmapped memory, `MemCpyAccessible` copies intersting range into temporarily buffer, and we search for pointers there.
1 parent c7496ce commit f4c6088

File tree

2 files changed

+43
-0
lines changed

2 files changed

+43
-0
lines changed

compiler-rt/lib/lsan/lsan_common.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,27 @@ struct DirectMemoryAccessor {
293293
void Init(uptr begin, uptr end) {};
294294
void *LoadPtr(uptr p) const { return *reinterpret_cast<void **>(p); }
295295
};
296+
297+
struct CopyMemoryAccessor {
298+
void Init(uptr begin, uptr end) {
299+
this->begin = begin;
300+
buffer.clear();
301+
buffer.resize(end - begin);
302+
MemCpyAccessible(buffer.data(), reinterpret_cast<void *>(begin),
303+
buffer.size());
304+
};
305+
306+
void *LoadPtr(uptr p) const {
307+
uptr offset = p - begin;
308+
CHECK_LE(offset + sizeof(void *), reinterpret_cast<uptr>(buffer.size()));
309+
return *reinterpret_cast<void **>(offset +
310+
reinterpret_cast<uptr>(buffer.data()));
311+
}
312+
313+
private:
314+
uptr begin;
315+
InternalMmapVector<char> buffer;
316+
};
296317
} // namespace
297318

298319
// Scans the memory range, looking for byte patterns that point into allocator
@@ -535,6 +556,7 @@ static void ProcessThread(tid_t os_id, uptr sp,
535556
static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
536557
Frontier *frontier, tid_t caller_tid,
537558
uptr caller_sp) {
559+
InternalMmapVector<tid_t> done_threads;
538560
InternalMmapVector<uptr> registers;
539561
InternalMmapVector<Range> extra_ranges;
540562
for (uptr i = 0; i < suspended_threads.ThreadCount(); i++) {
@@ -559,6 +581,25 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
559581

560582
DirectMemoryAccessor accessor;
561583
ProcessThread(os_id, sp, registers, extra_ranges, frontier, accessor);
584+
if (flags()->use_detached)
585+
done_threads.push_back(os_id);
586+
}
587+
588+
if (flags()->use_detached) {
589+
CopyMemoryAccessor accessor;
590+
InternalMmapVector<tid_t> known_threads;
591+
GetRunningThreadsLocked(&known_threads);
592+
Sort(done_threads.data(), done_threads.size());
593+
for (tid_t os_id : known_threads) {
594+
registers.clear();
595+
extra_ranges.clear();
596+
597+
uptr i = InternalLowerBound(done_threads, os_id);
598+
if (i >= done_threads.size() || done_threads[i] != os_id) {
599+
uptr sp = (os_id == caller_tid) ? caller_sp : 0;
600+
ProcessThread(os_id, sp, registers, extra_ranges, frontier, accessor);
601+
}
602+
}
562603
}
563604

564605
// Add pointers reachable from ThreadContexts

compiler-rt/lib/lsan/lsan_flags.inc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ LSAN_FLAG(bool, use_ld_allocations, true,
4141
LSAN_FLAG(bool, use_unaligned, false, "Consider unaligned pointers valid.")
4242
LSAN_FLAG(bool, use_poisoned, false,
4343
"Consider pointers found in poisoned memory to be valid.")
44+
LSAN_FLAG(bool, use_detached, false,
45+
"Scan threads even if attaching to them failed.")
4446
LSAN_FLAG(bool, log_pointers, false, "Debug logging")
4547
LSAN_FLAG(bool, log_threads, false, "Debug logging")
4648
LSAN_FLAG(int, tries, 1, "Debug option to repeat leak checking multiple times")

0 commit comments

Comments
 (0)