[compiler-rt] f4c6088 - [lsan] Process non-suspended threads (#112807)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Oct 18 15:23:55 PDT 2024
Author: Vitaly Buka
Date: 2024-10-18T15:23:52-07:00
New Revision: f4c6088346fa284412f13a24116836ff64b6bd4b
URL: https://github.com/llvm/llvm-project/commit/f4c6088346fa284412f13a24116836ff64b6bd4b
DIFF: https://github.com/llvm/llvm-project/commit/f4c6088346fa284412f13a24116836ff64b6bd4b.diff
LOG: [lsan] Process non-suspended threads (#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.
Added:
Modified:
compiler-rt/lib/lsan/lsan_common.cpp
compiler-rt/lib/lsan/lsan_flags.inc
Removed:
################################################################################
diff --git a/compiler-rt/lib/lsan/lsan_common.cpp b/compiler-rt/lib/lsan/lsan_common.cpp
index 9aed36b96ce929..bcb7baa6c530d2 100644
--- a/compiler-rt/lib/lsan/lsan_common.cpp
+++ b/compiler-rt/lib/lsan/lsan_common.cpp
@@ -293,6 +293,27 @@ struct DirectMemoryAccessor {
void Init(uptr begin, uptr end) {};
void *LoadPtr(uptr p) const { return *reinterpret_cast<void **>(p); }
};
+
+struct CopyMemoryAccessor {
+ void Init(uptr begin, uptr end) {
+ this->begin = begin;
+ buffer.clear();
+ buffer.resize(end - begin);
+ MemCpyAccessible(buffer.data(), reinterpret_cast<void *>(begin),
+ buffer.size());
+ };
+
+ void *LoadPtr(uptr p) const {
+ uptr offset = p - begin;
+ CHECK_LE(offset + sizeof(void *), reinterpret_cast<uptr>(buffer.size()));
+ return *reinterpret_cast<void **>(offset +
+ reinterpret_cast<uptr>(buffer.data()));
+ }
+
+ private:
+ uptr begin;
+ InternalMmapVector<char> buffer;
+};
} // namespace
// 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,
static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
Frontier *frontier, tid_t caller_tid,
uptr caller_sp) {
+ InternalMmapVector<tid_t> done_threads;
InternalMmapVector<uptr> registers;
InternalMmapVector<Range> extra_ranges;
for (uptr i = 0; i < suspended_threads.ThreadCount(); i++) {
@@ -559,6 +581,25 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
DirectMemoryAccessor accessor;
ProcessThread(os_id, sp, registers, extra_ranges, frontier, accessor);
+ if (flags()->use_detached)
+ done_threads.push_back(os_id);
+ }
+
+ if (flags()->use_detached) {
+ CopyMemoryAccessor accessor;
+ InternalMmapVector<tid_t> known_threads;
+ GetRunningThreadsLocked(&known_threads);
+ Sort(done_threads.data(), done_threads.size());
+ for (tid_t os_id : known_threads) {
+ registers.clear();
+ extra_ranges.clear();
+
+ uptr i = InternalLowerBound(done_threads, os_id);
+ if (i >= done_threads.size() || done_threads[i] != os_id) {
+ uptr sp = (os_id == caller_tid) ? caller_sp : 0;
+ ProcessThread(os_id, sp, registers, extra_ranges, frontier, accessor);
+ }
+ }
}
// Add pointers reachable from ThreadContexts
diff --git a/compiler-rt/lib/lsan/lsan_flags.inc b/compiler-rt/lib/lsan/lsan_flags.inc
index c97b021ba5c02f..e0b4aa4a3299e9 100644
--- a/compiler-rt/lib/lsan/lsan_flags.inc
+++ b/compiler-rt/lib/lsan/lsan_flags.inc
@@ -41,6 +41,8 @@ LSAN_FLAG(bool, use_ld_allocations, true,
LSAN_FLAG(bool, use_unaligned, false, "Consider unaligned pointers valid.")
LSAN_FLAG(bool, use_poisoned, false,
"Consider pointers found in poisoned memory to be valid.")
+LSAN_FLAG(bool, use_detached, false,
+ "Scan threads even if attaching to them failed.")
LSAN_FLAG(bool, log_pointers, false, "Debug logging")
LSAN_FLAG(bool, log_threads, false, "Debug logging")
LSAN_FLAG(int, tries, 1, "Debug option to repeat leak checking multiple times")
More information about the llvm-commits
mailing list