| 479 | // Scans thread data (stacks and TLS) for heap pointers. |
| 480 | template <class Accessor> |
| 481 | static void ProcessThread(tid_t os_id, uptr sp, |
| 482 | const InternalMmapVector<uptr> ®isters, |
| 483 | InternalMmapVector<Range> &extra_ranges, |
| 484 | Frontier *frontier, Accessor &accessor) { |
| 485 | // `extra_ranges` is outside of the function and the loop to reused mapped |
| 486 | // memory. |
| 487 | CHECK(extra_ranges.empty()); |
| 488 | LOG_THREADS("Processing thread %llu.\n", os_id); |
| 489 | uptr stack_begin, stack_end, tls_begin, tls_end, cache_begin, cache_end; |
| 490 | DTLS *dtls; |
| 491 | bool thread_found = |
| 492 | GetThreadRangesLocked(os_id, &stack_begin, &stack_end, &tls_begin, |
| 493 | &tls_end, &cache_begin, &cache_end, &dtls); |
| 494 | if (!thread_found) { |
| 495 | // If a thread can't be found in the thread registry, it's probably in the |
| 496 | // process of destruction. Log this event and move on. |
| 497 | LOG_THREADS("Thread %llu not found in registry.\n", os_id); |
| 498 | return; |
| 499 | } |
| 500 | |
| 501 | if (!sp) |
| 502 | sp = stack_begin; |
| 503 | |
| 504 | if (flags()->use_registers) { |
| 505 | uptr registers_begin = reinterpret_cast<uptr>(registers.data()); |
| 506 | uptr registers_end = |
| 507 | reinterpret_cast<uptr>(registers.data() + registers.size()); |
| 508 | ScanForPointers(registers_begin, registers_end, frontier, "REGISTERS", |
| 509 | kReachable, accessor); |
| 510 | } |
| 511 | |
| 512 | if (flags()->use_stacks) { |
| 513 | LOG_THREADS("Stack at %p-%p (SP = %p).\n", (void *)stack_begin, |
| 514 | (void *)stack_end, (void *)sp); |
| 515 | if (sp < stack_begin || sp >= stack_end) { |
| 516 | // SP is outside the recorded stack range (e.g. the thread is running a |
| 517 | // signal handler on alternate stack, or swapcontext was used). |
| 518 | // Again, consider the entire stack range to be reachable. |
| 519 | LOG_THREADS("WARNING: stack pointer not in stack range.\n"); |
| 520 | uptr page_size = GetPageSizeCached(); |
| 521 | int skipped = 0; |
| 522 | while (stack_begin < stack_end && |
| 523 | !IsAccessibleMemoryRange(stack_begin, 1)) { |
| 524 | skipped++; |
| 525 | stack_begin += page_size; |
| 526 | } |
| 527 | LOG_THREADS("Skipped %d guard page(s) to obtain stack %p-%p.\n", skipped, |
| 528 | (void *)stack_begin, (void *)stack_end); |
| 529 | } else { |
| 530 | // Shrink the stack range to ignore out-of-scope values. |
| 531 | stack_begin = sp; |
| 532 | } |
| 533 | ScanForPointers(stack_begin, stack_end, frontier, "STACK", kReachable, |
| 534 | accessor); |
| 535 | GetThreadExtraStackRangesLocked(os_id, &extra_ranges); |
| 536 | ScanRanges(extra_ranges, frontier, "FAKE STACK", accessor); |
| 537 | } |
| 538 |
no test coverage detected