Skip to content

Commit a04c4c8

Browse files
committed
[𝘀𝗽𝗿] initial version
Created using spr 1.3.4
2 parents 7106de9 + 733d50b commit a04c4c8

File tree

2 files changed

+91
-21
lines changed

2 files changed

+91
-21
lines changed

compiler-rt/lib/lsan/lsan_common.cpp

Lines changed: 89 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -288,23 +288,54 @@ static inline bool MaybeUserPointer(uptr p) {
288288
# endif
289289
}
290290

291+
namespace {
292+
struct DirectMemoryAccessor {
293+
void Init(uptr begin, uptr end) {};
294+
void *LoadPtr(uptr p) const { return *reinterpret_cast<void **>(p); }
295+
};
296+
297+
struct CopyLoader {
298+
void Init(uptr begin, uptr end) {
299+
buffer.clear();
300+
buffer.resize(end - begin);
301+
offset = reinterpret_cast<uptr>(buffer.data()) - begin;
302+
303+
// Need a partial data?
304+
MemCpyAccessible(buffer.data(), reinterpret_cast<void *>(begin),
305+
buffer.size());
306+
};
307+
void *LoadPtr(uptr p) const {
308+
CHECK_LE(p + offset + sizeof(void *),
309+
reinterpret_cast<uptr>(buffer.data() + buffer.size()));
310+
return *reinterpret_cast<void **>(p + offset);
311+
}
312+
313+
private:
314+
uptr offset;
315+
InternalMmapVector<char> buffer;
316+
};
317+
} // namespace
318+
291319
// Scans the memory range, looking for byte patterns that point into allocator
292320
// chunks. Marks those chunks with |tag| and adds them to |frontier|.
293321
// There are two usage modes for this function: finding reachable chunks
294322
// (|tag| = kReachable) and finding indirectly leaked chunks
295323
// (|tag| = kIndirectlyLeaked). In the second case, there's no flood fill,
296324
// so |frontier| = 0.
297-
void ScanRangeForPointers(uptr begin, uptr end, Frontier *frontier,
298-
const char *region_type, ChunkTag tag) {
325+
template <class Accessor>
326+
void ScanForPointers(uptr begin, uptr end, Frontier *frontier,
327+
const char *region_type, ChunkTag tag,
328+
Accessor &accessor) {
299329
CHECK(tag == kReachable || tag == kIndirectlyLeaked);
300330
const uptr alignment = flags()->pointer_alignment();
301331
LOG_POINTERS("Scanning %s range %p-%p.\n", region_type, (void *)begin,
302332
(void *)end);
333+
accessor.Init(begin, end);
303334
uptr pp = begin;
304335
if (pp % alignment)
305336
pp = pp + alignment - pp % alignment;
306337
for (; pp + sizeof(void *) <= end; pp += alignment) {
307-
void *p = *reinterpret_cast<void **>(pp);
338+
void *p = accessor.LoadPtr(pp);
308339
# if SANITIZER_APPLE
309340
p = TransformPointer(p);
310341
# endif
@@ -339,6 +370,12 @@ void ScanRangeForPointers(uptr begin, uptr end, Frontier *frontier,
339370
}
340371
}
341372

373+
void ScanRangeForPointers(uptr begin, uptr end, Frontier *frontier,
374+
const char *region_type, ChunkTag tag) {
375+
DirectMemoryAccessor accessor;
376+
ScanForPointers(begin, end, frontier, region_type, tag, accessor);
377+
}
378+
342379
// Scans a global range for pointers
343380
void ScanGlobalRange(uptr begin, uptr end, Frontier *frontier) {
344381
uptr allocator_begin = 0, allocator_end = 0;
@@ -356,14 +393,21 @@ void ScanGlobalRange(uptr begin, uptr end, Frontier *frontier) {
356393
}
357394
}
358395

359-
void ScanExtraStackRanges(const InternalMmapVector<Range> &ranges,
360-
Frontier *frontier) {
396+
template <class Accessor>
397+
void ScanExtraStack(const InternalMmapVector<Range> &ranges, Frontier *frontier,
398+
Accessor &accessor) {
361399
for (uptr i = 0; i < ranges.size(); i++) {
362-
ScanRangeForPointers(ranges[i].begin, ranges[i].end, frontier, "FAKE STACK",
363-
kReachable);
400+
ScanForPointers(ranges[i].begin, ranges[i].end, frontier, "FAKE STACK",
401+
kReachable, accessor);
364402
}
365403
}
366404

405+
void ScanExtraStackRanges(const InternalMmapVector<Range> &ranges,
406+
Frontier *frontier) {
407+
DirectMemoryAccessor accessor;
408+
ScanExtraStack(ranges, frontier, accessor);
409+
}
410+
367411
# if SANITIZER_FUCHSIA
368412

369413
// Fuchsia handles all threads together with its own callback.
@@ -399,10 +443,11 @@ static void ProcessThreadRegistry(Frontier *frontier) {
399443
}
400444

401445
// Scans thread data (stacks and TLS) for heap pointers.
446+
template <class Accessor>
402447
static void ProcessThread(tid_t os_id, uptr sp,
403448
const InternalMmapVector<uptr> &registers,
404449
InternalMmapVector<Range> &extra_ranges,
405-
Frontier *frontier) {
450+
Frontier *frontier, Accessor &accessor) {
406451
// `extra_ranges` is outside of the function and the loop to reused mapped
407452
// memory.
408453
CHECK(extra_ranges.empty());
@@ -426,8 +471,8 @@ static void ProcessThread(tid_t os_id, uptr sp,
426471
uptr registers_begin = reinterpret_cast<uptr>(registers.data());
427472
uptr registers_end =
428473
reinterpret_cast<uptr>(registers.data() + registers.size());
429-
ScanRangeForPointers(registers_begin, registers_end, frontier, "REGISTERS",
430-
kReachable);
474+
ScanForPointers(registers_begin, registers_end, frontier, "REGISTERS",
475+
kReachable, accessor);
431476
}
432477

433478
if (flags()->use_stacks) {
@@ -451,9 +496,10 @@ static void ProcessThread(tid_t os_id, uptr sp,
451496
// Shrink the stack range to ignore out-of-scope values.
452497
stack_begin = sp;
453498
}
454-
ScanRangeForPointers(stack_begin, stack_end, frontier, "STACK", kReachable);
499+
ScanForPointers(stack_begin, stack_end, frontier, "STACK", kReachable,
500+
accessor);
455501
GetThreadExtraStackRangesLocked(os_id, &extra_ranges);
456-
ScanExtraStackRanges(extra_ranges, frontier);
502+
ScanExtraStack(extra_ranges, frontier, accessor);
457503
}
458504

459505
if (flags()->use_tls) {
@@ -463,21 +509,23 @@ static void ProcessThread(tid_t os_id, uptr sp,
463509
// otherwise, only scan the non-overlapping portions
464510
if (cache_begin == cache_end || tls_end < cache_begin ||
465511
tls_begin > cache_end) {
466-
ScanRangeForPointers(tls_begin, tls_end, frontier, "TLS", kReachable);
512+
ScanForPointers(tls_begin, tls_end, frontier, "TLS", kReachable,
513+
accessor);
467514
} else {
468515
if (tls_begin < cache_begin)
469-
ScanRangeForPointers(tls_begin, cache_begin, frontier, "TLS",
470-
kReachable);
516+
ScanForPointers(tls_begin, cache_begin, frontier, "TLS", kReachable,
517+
accessor);
471518
if (tls_end > cache_end)
472-
ScanRangeForPointers(cache_end, tls_end, frontier, "TLS", kReachable);
519+
ScanForPointers(cache_end, tls_end, frontier, "TLS", kReachable,
520+
accessor);
473521
}
474522
}
475523
# if SANITIZER_ANDROID
476524
auto *cb = +[](void *dtls_begin, void *dtls_end, uptr /*dso_idd*/,
477525
void *arg) -> void {
478-
ScanRangeForPointers(
526+
ScanForPointers(
479527
reinterpret_cast<uptr>(dtls_begin), reinterpret_cast<uptr>(dtls_end),
480-
reinterpret_cast<Frontier *>(arg), "DTLS", kReachable);
528+
reinterpret_cast<Frontier *>(arg), "DTLS", kReachable, accessor);
481529
};
482530

483531
// FIXME: There might be a race-condition here (and in Bionic) if the
@@ -492,8 +540,8 @@ static void ProcessThread(tid_t os_id, uptr sp,
492540
if (dtls_beg < dtls_end) {
493541
LOG_THREADS("DTLS %d at %p-%p.\n", id, (void *)dtls_beg,
494542
(void *)dtls_end);
495-
ScanRangeForPointers(dtls_beg, dtls_end, frontier, "DTLS",
496-
kReachable);
543+
ScanForPointers(dtls_beg, dtls_end, frontier, "DTLS", kReachable,
544+
accessor);
497545
}
498546
});
499547
} else {
@@ -508,6 +556,7 @@ static void ProcessThread(tid_t os_id, uptr sp,
508556
static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
509557
Frontier *frontier, tid_t caller_tid,
510558
uptr caller_sp) {
559+
InternalMmapVector<tid_t> done_threads;
511560
InternalMmapVector<uptr> registers;
512561
InternalMmapVector<Range> extra_ranges;
513562
for (uptr i = 0; i < suspended_threads.ThreadCount(); i++) {
@@ -530,7 +579,26 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
530579
if (os_id == caller_tid)
531580
sp = caller_sp;
532581

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

536604
// 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 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)