@@ -399,6 +399,112 @@ 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> ®isters,
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+
402508static void ProcessThreads (SuspendedThreadsList const &suspended_threads,
403509 Frontier *frontier, tid_t caller_tid,
404510 uptr caller_sp) {
@@ -408,7 +514,7 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
408514 registers.clear ();
409515 extra_ranges.clear ();
410516
411- const tid_t os_id = static_cast < tid_t >( suspended_threads.GetThreadID (i) );
517+ const tid_t os_id = suspended_threads.GetThreadID (i);
412518 uptr sp = 0 ;
413519 PtraceRegistersStatus have_registers =
414520 suspended_threads.GetRegistersAndSP (i, ®isters, &sp);
@@ -421,109 +527,10 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
421527 sp = 0 ;
422528 }
423529
424- LOG_THREADS (" Processing thread %llu.\n " , os_id);
425- uptr stack_begin, stack_end, tls_begin, tls_end, cache_begin, cache_end;
426- DTLS *dtls;
427- bool thread_found =
428- GetThreadRangesLocked (os_id, &stack_begin, &stack_end, &tls_begin,
429- &tls_end, &cache_begin, &cache_end, &dtls);
430- if (!thread_found) {
431- // If a thread can't be found in the thread registry, it's probably in the
432- // process of destruction. Log this event and move on.
433- LOG_THREADS (" Thread %llu not found in registry.\n " , os_id);
434- continue ;
435- }
436-
437530 if (os_id == caller_tid)
438531 sp = caller_sp;
439532
440- if (!sp)
441- sp = stack_begin;
442-
443- if (flags ()->use_registers && have_registers) {
444- uptr registers_begin = reinterpret_cast <uptr>(registers.data ());
445- uptr registers_end =
446- reinterpret_cast <uptr>(registers.data () + registers.size ());
447- ScanRangeForPointers (registers_begin, registers_end, frontier,
448- " REGISTERS" , kReachable );
449- }
450-
451- if (flags ()->use_stacks ) {
452- LOG_THREADS (" Stack at %p-%p (SP = %p).\n " , (void *)stack_begin,
453- (void *)stack_end, (void *)sp);
454- if (sp < stack_begin || sp >= stack_end) {
455- // SP is outside the recorded stack range (e.g. the thread is running a
456- // signal handler on alternate stack, or swapcontext was used).
457- // Again, consider the entire stack range to be reachable.
458- LOG_THREADS (" WARNING: stack pointer not in stack range.\n " );
459- uptr page_size = GetPageSizeCached ();
460- int skipped = 0 ;
461- while (stack_begin < stack_end &&
462- !IsAccessibleMemoryRange (stack_begin, 1 )) {
463- skipped++;
464- stack_begin += page_size;
465- }
466- LOG_THREADS (" Skipped %d guard page(s) to obtain stack %p-%p.\n " ,
467- skipped, (void *)stack_begin, (void *)stack_end);
468- } else {
469- // Shrink the stack range to ignore out-of-scope values.
470- stack_begin = sp;
471- }
472- ScanRangeForPointers (stack_begin, stack_end, frontier, " STACK" ,
473- kReachable );
474- GetThreadExtraStackRangesLocked (os_id, &extra_ranges);
475- ScanExtraStackRanges (extra_ranges, frontier);
476- }
477-
478- if (flags ()->use_tls ) {
479- if (tls_begin) {
480- LOG_THREADS (" TLS at %p-%p.\n " , (void *)tls_begin, (void *)tls_end);
481- // If the tls and cache ranges don't overlap, scan full tls range,
482- // otherwise, only scan the non-overlapping portions
483- if (cache_begin == cache_end || tls_end < cache_begin ||
484- tls_begin > cache_end) {
485- ScanRangeForPointers (tls_begin, tls_end, frontier, " TLS" , kReachable );
486- } else {
487- if (tls_begin < cache_begin)
488- ScanRangeForPointers (tls_begin, cache_begin, frontier, " TLS" ,
489- kReachable );
490- if (tls_end > cache_end)
491- ScanRangeForPointers (cache_end, tls_end, frontier, " TLS" ,
492- kReachable );
493- }
494- }
495- # if SANITIZER_ANDROID
496- auto *cb = +[](void *dtls_begin, void *dtls_end, uptr /* dso_idd*/ ,
497- void *arg) -> void {
498- ScanRangeForPointers (reinterpret_cast <uptr>(dtls_begin),
499- reinterpret_cast <uptr>(dtls_end),
500- reinterpret_cast <Frontier *>(arg), " DTLS" ,
501- kReachable );
502- };
503-
504- // FIXME: There might be a race-condition here (and in Bionic) if the
505- // thread is suspended in the middle of updating its DTLS. IOWs, we
506- // could scan already freed memory. (probably fine for now)
507- __libc_iterate_dynamic_tls (os_id, cb, frontier);
508- # else
509- if (dtls && !DTLSInDestruction (dtls)) {
510- ForEachDVT (dtls, [&](const DTLS::DTV &dtv, int id) {
511- uptr dtls_beg = dtv.beg ;
512- uptr dtls_end = dtls_beg + dtv.size ;
513- if (dtls_beg < dtls_end) {
514- LOG_THREADS (" DTLS %d at %p-%p.\n " , id, (void *)dtls_beg,
515- (void *)dtls_end);
516- ScanRangeForPointers (dtls_beg, dtls_end, frontier, " DTLS" ,
517- kReachable );
518- }
519- });
520- } else {
521- // We are handling a thread with DTLS under destruction. Log about
522- // this and continue.
523- LOG_THREADS (" Thread %llu has DTLS under destruction.\n " , os_id);
524- }
525- # endif
526- }
533+ ProcessThread (os_id, sp, registers, extra_ranges, frontier);
527534 }
528535
529536 // Add pointers reachable from ThreadContexts
0 commit comments