diff --git a/compiler-rt/lib/lsan/lsan_common.h b/compiler-rt/lib/lsan/lsan_common.h --- a/compiler-rt/lib/lsan/lsan_common.h +++ b/compiler-rt/lib/lsan/lsan_common.h @@ -126,12 +126,24 @@ uptr size; }; +// LockStuffAndStopTheWorld can start to use Scan* calls to collect into +// this Frontier vector before the StopTheWorldCallback actually runs. +// This is used when the OS has a unified callback API for suspending +// threads and enumerating roots. +struct CheckForLeaksParam { + Frontier frontier; + LeakReport leak_report; + bool success = false; +}; + InternalMmapVector const *GetRootRegions(); void ScanRootRegion(Frontier *frontier, RootRegion const ®ion, uptr region_begin, uptr region_end, bool is_readable); +void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg); // Run stoptheworld while holding any platform-specific locks, as well as the // allocator and thread registry locks. -void LockStuffAndStopTheWorld(StopTheWorldCallback callback, void* argument); +void LockStuffAndStopTheWorld(StopTheWorldCallback callback, + CheckForLeaksParam* argument); void ScanRangeForPointers(uptr begin, uptr end, Frontier *frontier, diff --git a/compiler-rt/lib/lsan/lsan_common.cpp b/compiler-rt/lib/lsan/lsan_common.cpp --- a/compiler-rt/lib/lsan/lsan_common.cpp +++ b/compiler-rt/lib/lsan/lsan_common.cpp @@ -443,25 +443,23 @@ } // Sets the appropriate tag on each chunk. -static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads) { - // Holds the flood fill frontier. - Frontier frontier; +static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads, + Frontier *frontier) { + ForEachChunk(CollectIgnoredCb, frontier); + ProcessGlobalRegions(frontier); + ProcessThreads(suspended_threads, frontier); + ProcessRootRegions(frontier); + FloodFillTag(frontier, kReachable); - ForEachChunk(CollectIgnoredCb, &frontier); - ProcessGlobalRegions(&frontier); - ProcessThreads(suspended_threads, &frontier); - ProcessRootRegions(&frontier); - FloodFillTag(&frontier, kReachable); - - CHECK_EQ(0, frontier.size()); - ProcessPC(&frontier); + CHECK_EQ(0, frontier->size()); + ProcessPC(frontier); // The check here is relatively expensive, so we do this in a separate flood // fill. That way we can skip the check for chunks that are reachable // otherwise. LOG_POINTERS("Processing platform-specific allocations.\n"); - ProcessPlatformSpecificAllocations(&frontier); - FloodFillTag(&frontier, kReachable); + ProcessPlatformSpecificAllocations(frontier); + FloodFillTag(frontier, kReachable); // Iterate over leaked chunks and mark those that are reachable from other // leaked chunks. @@ -521,11 +519,6 @@ Printf("%s\n\n", line); } -struct CheckForLeaksParam { - bool success; - LeakReport leak_report; -}; - static void ReportIfNotSuspended(ThreadContextBase *tctx, void *arg) { const InternalMmapVector &suspended_threads = *(const InternalMmapVector *)arg; @@ -556,7 +549,7 @@ CHECK(param); CHECK(!param->success); ReportUnsuspendedThreads(suspended_threads); - ClassifyAllChunks(suspended_threads); + ClassifyAllChunks(suspended_threads, ¶m->frontier); ForEachChunk(CollectLeaksCb, ¶m->leak_report); // Clean up for subsequent leak checks. This assumes we did not overwrite any // kIgnored tags. @@ -569,7 +562,6 @@ return false; EnsureMainThreadIDIsCorrect(); CheckForLeaksParam param; - param.success = false; LockStuffAndStopTheWorld(CheckForLeaksCallback, ¶m); if (!param.success) { diff --git a/compiler-rt/lib/lsan/lsan_common_linux.cpp b/compiler-rt/lib/lsan/lsan_common_linux.cpp --- a/compiler-rt/lib/lsan/lsan_common_linux.cpp +++ b/compiler-rt/lib/lsan/lsan_common_linux.cpp @@ -134,7 +134,8 @@ // while holding the libdl lock in the parent thread, we can safely reenter it // in the tracer. The solution is to run stoptheworld from a dl_iterate_phdr() // callback in the parent thread. -void LockStuffAndStopTheWorld(StopTheWorldCallback callback, void *argument) { +void LockStuffAndStopTheWorld(StopTheWorldCallback callback, + CheckForLeaksParam *argument) { DoStopTheWorldParam param = {callback, argument}; dl_iterate_phdr(LockStuffAndStopTheWorldCallback, ¶m); } diff --git a/compiler-rt/lib/lsan/lsan_common_mac.cpp b/compiler-rt/lib/lsan/lsan_common_mac.cpp --- a/compiler-rt/lib/lsan/lsan_common_mac.cpp +++ b/compiler-rt/lib/lsan/lsan_common_mac.cpp @@ -193,7 +193,8 @@ // causes rare race conditions. void HandleLeaks() {} -void LockStuffAndStopTheWorld(StopTheWorldCallback callback, void *argument) { +void LockStuffAndStopTheWorld(StopTheWorldCallback callback, + CheckForLeaksParam *argument) { LockThreadRegistry(); LockAllocator(); StopTheWorld(callback, argument);