@@ -399,6 +399,112 @@ static void ProcessThreadRegistry(Frontier *frontier) {
399
399
}
400
400
401
401
// 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
+
402
508
static void ProcessThreads (SuspendedThreadsList const &suspended_threads,
403
509
Frontier *frontier, tid_t caller_tid,
404
510
uptr caller_sp) {
@@ -408,7 +514,7 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
408
514
registers.clear ();
409
515
extra_ranges.clear ();
410
516
411
- const tid_t os_id = static_cast < tid_t >( suspended_threads.GetThreadID (i) );
517
+ const tid_t os_id = suspended_threads.GetThreadID (i);
412
518
uptr sp = 0 ;
413
519
PtraceRegistersStatus have_registers =
414
520
suspended_threads.GetRegistersAndSP (i, ®isters, &sp);
@@ -421,109 +527,10 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
421
527
sp = 0 ;
422
528
}
423
529
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
-
437
530
if (os_id == caller_tid)
438
531
sp = caller_sp;
439
532
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);
527
534
}
528
535
529
536
// Add pointers reachable from ThreadContexts
0 commit comments