@@ -288,23 +288,54 @@ static inline bool MaybeUserPointer(uptr p) {
288288# endif
289289}
290290
291+ namespace {
292+ struct DirectMemoryAccessor {
293+ void Init (uptr begin, uptr end) {};
294+ void *LoadPtr (uptr p) const { return *reinterpret_cast <void **>(p); }
295+ };
296+
297+ struct CopyLoader {
298+ void Init (uptr begin, uptr end) {
299+ buffer.clear ();
300+ buffer.resize (end - begin);
301+ offset = reinterpret_cast <uptr>(buffer.data ()) - begin;
302+
303+ // Need a partial data?
304+ MemCpyAccessible (buffer.data (), reinterpret_cast <void *>(begin),
305+ buffer.size ());
306+ };
307+ void *LoadPtr (uptr p) const {
308+ CHECK_LE (p + offset + sizeof (void *),
309+ reinterpret_cast <uptr>(buffer.data () + buffer.size ()));
310+ return *reinterpret_cast <void **>(p + offset);
311+ }
312+
313+ private:
314+ uptr offset;
315+ InternalMmapVector<char > buffer;
316+ };
317+ } // namespace
318+
291319// Scans the memory range, looking for byte patterns that point into allocator
292320// chunks. Marks those chunks with |tag| and adds them to |frontier|.
293321// There are two usage modes for this function: finding reachable chunks
294322// (|tag| = kReachable) and finding indirectly leaked chunks
295323// (|tag| = kIndirectlyLeaked). In the second case, there's no flood fill,
296324// so |frontier| = 0.
297- void ScanRangeForPointers (uptr begin, uptr end, Frontier *frontier,
298- const char *region_type, ChunkTag tag) {
325+ template <class Accessor >
326+ void ScanForPointers (uptr begin, uptr end, Frontier *frontier,
327+ const char *region_type, ChunkTag tag,
328+ Accessor &accessor) {
299329 CHECK (tag == kReachable || tag == kIndirectlyLeaked );
300330 const uptr alignment = flags ()->pointer_alignment ();
301331 LOG_POINTERS (" Scanning %s range %p-%p.\n " , region_type, (void *)begin,
302332 (void *)end);
333+ accessor.Init (begin, end);
303334 uptr pp = begin;
304335 if (pp % alignment)
305336 pp = pp + alignment - pp % alignment;
306337 for (; pp + sizeof (void *) <= end; pp += alignment) {
307- void *p = * reinterpret_cast < void **> (pp);
338+ void *p = accessor. LoadPtr (pp);
308339# if SANITIZER_APPLE
309340 p = TransformPointer (p);
310341# endif
@@ -339,6 +370,12 @@ void ScanRangeForPointers(uptr begin, uptr end, Frontier *frontier,
339370 }
340371}
341372
373+ void ScanRangeForPointers (uptr begin, uptr end, Frontier *frontier,
374+ const char *region_type, ChunkTag tag) {
375+ DirectMemoryAccessor accessor;
376+ ScanForPointers (begin, end, frontier, region_type, tag, accessor);
377+ }
378+
342379// Scans a global range for pointers
343380void ScanGlobalRange (uptr begin, uptr end, Frontier *frontier) {
344381 uptr allocator_begin = 0 , allocator_end = 0 ;
@@ -356,14 +393,21 @@ void ScanGlobalRange(uptr begin, uptr end, Frontier *frontier) {
356393 }
357394}
358395
359- void ScanExtraStackRanges (const InternalMmapVector<Range> &ranges,
360- Frontier *frontier) {
396+ template <class Accessor >
397+ void ScanExtraStack (const InternalMmapVector<Range> &ranges, Frontier *frontier,
398+ Accessor &accessor) {
361399 for (uptr i = 0 ; i < ranges.size (); i++) {
362- ScanRangeForPointers (ranges[i].begin , ranges[i].end , frontier, " FAKE STACK" ,
363- kReachable );
400+ ScanForPointers (ranges[i].begin , ranges[i].end , frontier, " FAKE STACK" ,
401+ kReachable , accessor );
364402 }
365403}
366404
405+ void ScanExtraStackRanges (const InternalMmapVector<Range> &ranges,
406+ Frontier *frontier) {
407+ DirectMemoryAccessor accessor;
408+ ScanExtraStack (ranges, frontier, accessor);
409+ }
410+
367411# if SANITIZER_FUCHSIA
368412
369413// Fuchsia handles all threads together with its own callback.
@@ -399,10 +443,11 @@ static void ProcessThreadRegistry(Frontier *frontier) {
399443}
400444
401445// Scans thread data (stacks and TLS) for heap pointers.
446+ template <class Accessor >
402447static void ProcessThread (tid_t os_id, uptr sp,
403448 const InternalMmapVector<uptr> ®isters,
404449 InternalMmapVector<Range> &extra_ranges,
405- Frontier *frontier) {
450+ Frontier *frontier, Accessor &accessor ) {
406451 // `extra_ranges` is outside of the function and the loop to reused mapped
407452 // memory.
408453 CHECK (extra_ranges.empty ());
@@ -426,8 +471,8 @@ static void ProcessThread(tid_t os_id, uptr sp,
426471 uptr registers_begin = reinterpret_cast <uptr>(registers.data ());
427472 uptr registers_end =
428473 reinterpret_cast <uptr>(registers.data () + registers.size ());
429- ScanRangeForPointers (registers_begin, registers_end, frontier, " REGISTERS" ,
430- kReachable );
474+ ScanForPointers (registers_begin, registers_end, frontier, " REGISTERS" ,
475+ kReachable , accessor );
431476 }
432477
433478 if (flags ()->use_stacks ) {
@@ -451,9 +496,10 @@ static void ProcessThread(tid_t os_id, uptr sp,
451496 // Shrink the stack range to ignore out-of-scope values.
452497 stack_begin = sp;
453498 }
454- ScanRangeForPointers (stack_begin, stack_end, frontier, " STACK" , kReachable );
499+ ScanForPointers (stack_begin, stack_end, frontier, " STACK" , kReachable ,
500+ accessor);
455501 GetThreadExtraStackRangesLocked (os_id, &extra_ranges);
456- ScanExtraStackRanges (extra_ranges, frontier);
502+ ScanExtraStack (extra_ranges, frontier, accessor );
457503 }
458504
459505 if (flags ()->use_tls ) {
@@ -463,21 +509,23 @@ static void ProcessThread(tid_t os_id, uptr sp,
463509 // otherwise, only scan the non-overlapping portions
464510 if (cache_begin == cache_end || tls_end < cache_begin ||
465511 tls_begin > cache_end) {
466- ScanRangeForPointers (tls_begin, tls_end, frontier, " TLS" , kReachable );
512+ ScanForPointers (tls_begin, tls_end, frontier, " TLS" , kReachable ,
513+ accessor);
467514 } else {
468515 if (tls_begin < cache_begin)
469- ScanRangeForPointers (tls_begin, cache_begin, frontier, " TLS" ,
470- kReachable );
516+ ScanForPointers (tls_begin, cache_begin, frontier, " TLS" , kReachable ,
517+ accessor );
471518 if (tls_end > cache_end)
472- ScanRangeForPointers (cache_end, tls_end, frontier, " TLS" , kReachable );
519+ ScanForPointers (cache_end, tls_end, frontier, " TLS" , kReachable ,
520+ accessor);
473521 }
474522 }
475523# if SANITIZER_ANDROID
476524 auto *cb = +[](void *dtls_begin, void *dtls_end, uptr /* dso_idd*/ ,
477525 void *arg) -> void {
478- ScanRangeForPointers (
526+ ScanForPointers (
479527 reinterpret_cast <uptr>(dtls_begin), reinterpret_cast <uptr>(dtls_end),
480- reinterpret_cast <Frontier *>(arg), " DTLS" , kReachable );
528+ reinterpret_cast <Frontier *>(arg), " DTLS" , kReachable , accessor );
481529 };
482530
483531 // FIXME: There might be a race-condition here (and in Bionic) if the
@@ -492,8 +540,8 @@ static void ProcessThread(tid_t os_id, uptr sp,
492540 if (dtls_beg < dtls_end) {
493541 LOG_THREADS (" DTLS %d at %p-%p.\n " , id, (void *)dtls_beg,
494542 (void *)dtls_end);
495- ScanRangeForPointers (dtls_beg, dtls_end, frontier, " DTLS" ,
496- kReachable );
543+ ScanForPointers (dtls_beg, dtls_end, frontier, " DTLS" , kReachable ,
544+ accessor );
497545 }
498546 });
499547 } else {
@@ -508,6 +556,7 @@ static void ProcessThread(tid_t os_id, uptr sp,
508556static void ProcessThreads (SuspendedThreadsList const &suspended_threads,
509557 Frontier *frontier, tid_t caller_tid,
510558 uptr caller_sp) {
559+ InternalMmapVector<tid_t > done_threads;
511560 InternalMmapVector<uptr> registers;
512561 InternalMmapVector<Range> extra_ranges;
513562 for (uptr i = 0 ; i < suspended_threads.ThreadCount (); i++) {
@@ -530,7 +579,26 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
530579 if (os_id == caller_tid)
531580 sp = caller_sp;
532581
533- ProcessThread (os_id, sp, registers, extra_ranges, frontier);
582+ DirectMemoryAccessor accessor;
583+ ProcessThread (os_id, sp, registers, extra_ranges, frontier, accessor);
584+ done_threads.push_back (os_id);
585+ }
586+
587+ if (flags ()->use_detached ) {
588+ CopyLoader accessor;
589+ InternalMmapVector<tid_t > known_threads;
590+ GetRunningThreadsLocked (&known_threads);
591+ Sort (done_threads.data (), done_threads.size ());
592+ for (tid_t os_id : known_threads) {
593+ registers.clear ();
594+ extra_ranges.clear ();
595+
596+ uptr i = InternalLowerBound (done_threads, os_id);
597+ if (i >= done_threads.size () || done_threads[i] != os_id) {
598+ uptr sp = (os_id == caller_tid) ? caller_sp : 0 ;
599+ ProcessThread (os_id, sp, registers, extra_ranges, frontier, accessor);
600+ }
601+ }
534602 }
535603
536604 // Add pointers reachable from ThreadContexts
0 commit comments