@@ -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> ®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) {
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, ®isters, &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