Skip to content

Commit 8bbcf00

Browse files
committed
[𝘀𝗽𝗿] initial version
Created using spr 1.3.4
2 parents 37ad65f + 3a24624 commit 8bbcf00

File tree

1 file changed

+115
-102
lines changed

1 file changed

+115
-102
lines changed

compiler-rt/lib/lsan/lsan_common.cpp

Lines changed: 115 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -399,26 +399,123 @@ static void ProcessThreadRegistry(Frontier *frontier) {
399399
}
400400

401401
// Scans thread data (stacks and TLS) for heap pointers.
402+
static void ProcessThread(tid_t os_id, uptr sp,
403+
const InternalMmapVector<uptr> &registers,
404+
InternalMmapVector<Range> &extra_ranges,
405+
Frontier *frontier) {
406+
// `extra_ranges` is outside of the function and the loop to reused mapped
407+
// memory.
408+
CHECK(extra_ranges.empty());
409+
LOG_THREADS("Processing thread %llu.\n", os_id);
410+
uptr stack_begin, stack_end, tls_begin, tls_end, cache_begin, cache_end;
411+
DTLS *dtls;
412+
bool thread_found =
413+
GetThreadRangesLocked(os_id, &stack_begin, &stack_end, &tls_begin,
414+
&tls_end, &cache_begin, &cache_end, &dtls);
415+
if (!thread_found) {
416+
// If a thread can't be found in the thread registry, it's probably in the
417+
// process of destruction. Log this event and move on.
418+
LOG_THREADS("Thread %llu not found in registry.\n", os_id);
419+
return;
420+
}
421+
422+
if (!sp)
423+
sp = stack_begin;
424+
425+
if (flags()->use_registers) {
426+
uptr registers_begin = reinterpret_cast<uptr>(registers.data());
427+
uptr registers_end =
428+
reinterpret_cast<uptr>(registers.data() + registers.size());
429+
ScanRangeForPointers(registers_begin, registers_end, frontier, "REGISTERS",
430+
kReachable);
431+
}
432+
433+
if (flags()->use_stacks) {
434+
LOG_THREADS("Stack at %p-%p (SP = %p).\n", (void *)stack_begin,
435+
(void *)stack_end, (void *)sp);
436+
if (sp < stack_begin || sp >= stack_end) {
437+
// SP is outside the recorded stack range (e.g. the thread is running a
438+
// signal handler on alternate stack, or swapcontext was used).
439+
// Again, consider the entire stack range to be reachable.
440+
LOG_THREADS("WARNING: stack pointer not in stack range.\n");
441+
uptr page_size = GetPageSizeCached();
442+
int skipped = 0;
443+
while (stack_begin < stack_end &&
444+
!IsAccessibleMemoryRange(stack_begin, 1)) {
445+
skipped++;
446+
stack_begin += page_size;
447+
}
448+
LOG_THREADS("Skipped %d guard page(s) to obtain stack %p-%p.\n", skipped,
449+
(void *)stack_begin, (void *)stack_end);
450+
} else {
451+
// Shrink the stack range to ignore out-of-scope values.
452+
stack_begin = sp;
453+
}
454+
ScanRangeForPointers(stack_begin, stack_end, frontier, "STACK", kReachable);
455+
GetThreadExtraStackRangesLocked(os_id, &extra_ranges);
456+
ScanExtraStackRanges(extra_ranges, frontier);
457+
}
458+
459+
if (flags()->use_tls) {
460+
if (tls_begin) {
461+
LOG_THREADS("TLS at %p-%p.\n", (void *)tls_begin, (void *)tls_end);
462+
// If the tls and cache ranges don't overlap, scan full tls range,
463+
// otherwise, only scan the non-overlapping portions
464+
if (cache_begin == cache_end || tls_end < cache_begin ||
465+
tls_begin > cache_end) {
466+
ScanRangeForPointers(tls_begin, tls_end, frontier, "TLS", kReachable);
467+
} else {
468+
if (tls_begin < cache_begin)
469+
ScanRangeForPointers(tls_begin, cache_begin, frontier, "TLS",
470+
kReachable);
471+
if (tls_end > cache_end)
472+
ScanRangeForPointers(cache_end, tls_end, frontier, "TLS", kReachable);
473+
}
474+
}
475+
# if SANITIZER_ANDROID
476+
auto *cb = +[](void *dtls_begin, void *dtls_end, uptr /*dso_idd*/,
477+
void *arg) -> void {
478+
ScanRangeForPointers(
479+
reinterpret_cast<uptr>(dtls_begin), reinterpret_cast<uptr>(dtls_end),
480+
reinterpret_cast<Frontier *>(arg), "DTLS", kReachable);
481+
};
482+
483+
// FIXME: There might be a race-condition here (and in Bionic) if the
484+
// thread is suspended in the middle of updating its DTLS. IOWs, we
485+
// could scan already freed memory. (probably fine for now)
486+
__libc_iterate_dynamic_tls(os_id, cb, frontier);
487+
# else
488+
if (dtls && !DTLSInDestruction(dtls)) {
489+
ForEachDVT(dtls, [&](const DTLS::DTV &dtv, int id) {
490+
uptr dtls_beg = dtv.beg;
491+
uptr dtls_end = dtls_beg + dtv.size;
492+
if (dtls_beg < dtls_end) {
493+
LOG_THREADS("DTLS %d at %p-%p.\n", id, (void *)dtls_beg,
494+
(void *)dtls_end);
495+
ScanRangeForPointers(dtls_beg, dtls_end, frontier, "DTLS",
496+
kReachable);
497+
}
498+
});
499+
} else {
500+
// We are handling a thread with DTLS under destruction. Log about
501+
// this and continue.
502+
LOG_THREADS("Thread %llu has DTLS under destruction.\n", os_id);
503+
}
504+
# endif
505+
}
506+
}
507+
402508
static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
403509
Frontier *frontier, tid_t caller_tid,
404510
uptr caller_sp) {
405511
InternalMmapVector<uptr> registers;
406512
InternalMmapVector<Range> extra_ranges;
407513
for (uptr i = 0; i < suspended_threads.ThreadCount(); i++) {
408-
tid_t os_id = static_cast<tid_t>(suspended_threads.GetThreadID(i));
409-
LOG_THREADS("Processing thread %llu.\n", os_id);
410-
uptr stack_begin, stack_end, tls_begin, tls_end, cache_begin, cache_end;
411-
DTLS *dtls;
412-
bool thread_found =
413-
GetThreadRangesLocked(os_id, &stack_begin, &stack_end, &tls_begin,
414-
&tls_end, &cache_begin, &cache_end, &dtls);
415-
if (!thread_found) {
416-
// If a thread can't be found in the thread registry, it's probably in the
417-
// process of destruction. Log this event and move on.
418-
LOG_THREADS("Thread %llu not found in registry.\n", os_id);
419-
continue;
420-
}
421-
uptr sp;
514+
registers.clear();
515+
extra_ranges.clear();
516+
517+
const tid_t os_id = suspended_threads.GetThreadID(i);
518+
uptr sp = 0;
422519
PtraceRegistersStatus have_registers =
423520
suspended_threads.GetRegistersAndSP(i, &registers, &sp);
424521
if (have_registers != REGISTERS_AVAILABLE) {
@@ -427,97 +524,13 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
427524
// GetRegistersAndSP failed with ESRCH.
428525
if (have_registers == REGISTERS_UNAVAILABLE_FATAL)
429526
continue;
430-
sp = stack_begin;
431-
}
432-
if (suspended_threads.GetThreadID(i) == caller_tid) {
433-
sp = caller_sp;
527+
sp = 0;
434528
}
435529

436-
if (flags()->use_registers && have_registers) {
437-
uptr registers_begin = reinterpret_cast<uptr>(registers.data());
438-
uptr registers_end =
439-
reinterpret_cast<uptr>(registers.data() + registers.size());
440-
ScanRangeForPointers(registers_begin, registers_end, frontier,
441-
"REGISTERS", kReachable);
442-
}
443-
444-
if (flags()->use_stacks) {
445-
LOG_THREADS("Stack at %p-%p (SP = %p).\n", (void *)stack_begin,
446-
(void *)stack_end, (void *)sp);
447-
if (sp < stack_begin || sp >= stack_end) {
448-
// SP is outside the recorded stack range (e.g. the thread is running a
449-
// signal handler on alternate stack, or swapcontext was used).
450-
// Again, consider the entire stack range to be reachable.
451-
LOG_THREADS("WARNING: stack pointer not in stack range.\n");
452-
uptr page_size = GetPageSizeCached();
453-
int skipped = 0;
454-
while (stack_begin < stack_end &&
455-
!IsAccessibleMemoryRange(stack_begin, 1)) {
456-
skipped++;
457-
stack_begin += page_size;
458-
}
459-
LOG_THREADS("Skipped %d guard page(s) to obtain stack %p-%p.\n",
460-
skipped, (void *)stack_begin, (void *)stack_end);
461-
} else {
462-
// Shrink the stack range to ignore out-of-scope values.
463-
stack_begin = sp;
464-
}
465-
ScanRangeForPointers(stack_begin, stack_end, frontier, "STACK",
466-
kReachable);
467-
extra_ranges.clear();
468-
GetThreadExtraStackRangesLocked(os_id, &extra_ranges);
469-
ScanExtraStackRanges(extra_ranges, frontier);
470-
}
530+
if (os_id == caller_tid)
531+
sp = caller_sp;
471532

472-
if (flags()->use_tls) {
473-
if (tls_begin) {
474-
LOG_THREADS("TLS at %p-%p.\n", (void *)tls_begin, (void *)tls_end);
475-
// If the tls and cache ranges don't overlap, scan full tls range,
476-
// otherwise, only scan the non-overlapping portions
477-
if (cache_begin == cache_end || tls_end < cache_begin ||
478-
tls_begin > cache_end) {
479-
ScanRangeForPointers(tls_begin, tls_end, frontier, "TLS", kReachable);
480-
} else {
481-
if (tls_begin < cache_begin)
482-
ScanRangeForPointers(tls_begin, cache_begin, frontier, "TLS",
483-
kReachable);
484-
if (tls_end > cache_end)
485-
ScanRangeForPointers(cache_end, tls_end, frontier, "TLS",
486-
kReachable);
487-
}
488-
}
489-
# if SANITIZER_ANDROID
490-
auto *cb = +[](void *dtls_begin, void *dtls_end, uptr /*dso_idd*/,
491-
void *arg) -> void {
492-
ScanRangeForPointers(reinterpret_cast<uptr>(dtls_begin),
493-
reinterpret_cast<uptr>(dtls_end),
494-
reinterpret_cast<Frontier *>(arg), "DTLS",
495-
kReachable);
496-
};
497-
498-
// FIXME: There might be a race-condition here (and in Bionic) if the
499-
// thread is suspended in the middle of updating its DTLS. IOWs, we
500-
// could scan already freed memory. (probably fine for now)
501-
__libc_iterate_dynamic_tls(os_id, cb, frontier);
502-
# else
503-
if (dtls && !DTLSInDestruction(dtls)) {
504-
ForEachDVT(dtls, [&](const DTLS::DTV &dtv, int id) {
505-
uptr dtls_beg = dtv.beg;
506-
uptr dtls_end = dtls_beg + dtv.size;
507-
if (dtls_beg < dtls_end) {
508-
LOG_THREADS("DTLS %d at %p-%p.\n", id, (void *)dtls_beg,
509-
(void *)dtls_end);
510-
ScanRangeForPointers(dtls_beg, dtls_end, frontier, "DTLS",
511-
kReachable);
512-
}
513-
});
514-
} else {
515-
// We are handling a thread with DTLS under destruction. Log about
516-
// this and continue.
517-
LOG_THREADS("Thread %llu has DTLS under destruction.\n", os_id);
518-
}
519-
# endif
520-
}
533+
ProcessThread(os_id, sp, registers, extra_ranges, frontier);
521534
}
522535

523536
// Add pointers reachable from ThreadContexts

0 commit comments

Comments
 (0)