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 @@ -145,6 +145,8 @@ struct CheckForLeaksParam { Frontier frontier; LeakedChunks leaks; + tid_t caller_tid; + uptr caller_sp; bool success = false; }; 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 @@ -365,7 +365,8 @@ // Scans thread data (stacks and TLS) for heap pointers. static void ProcessThreads(SuspendedThreadsList const &suspended_threads, - Frontier *frontier) { + Frontier *frontier, tid_t caller_tid, + uptr caller_sp) { InternalMmapVector registers; for (uptr i = 0; i < suspended_threads.ThreadCount(); i++) { tid_t os_id = static_cast(suspended_threads.GetThreadID(i)); @@ -392,6 +393,9 @@ continue; sp = stack_begin; } + if (suspended_threads.GetThreadID(i) == caller_tid) { + sp = caller_sp; + } if (flags()->use_registers && have_registers) { uptr registers_begin = reinterpret_cast(registers.data()); @@ -572,7 +576,8 @@ // Sets the appropriate tag on each chunk. static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads, - Frontier *frontier) { + Frontier *frontier, tid_t caller_tid, + uptr caller_sp) { const InternalMmapVector &suppressed_stacks = GetSuppressionContext()->GetSortedSuppressedStacks(); if (!suppressed_stacks.empty()) { @@ -581,7 +586,7 @@ } ForEachChunk(CollectIgnoredCb, frontier); ProcessGlobalRegions(frontier); - ProcessThreads(suspended_threads, frontier); + ProcessThreads(suspended_threads, frontier, caller_tid, caller_sp); ProcessRootRegions(frontier); FloodFillTag(frontier, kReachable); @@ -677,7 +682,8 @@ CHECK(param); CHECK(!param->success); ReportUnsuspendedThreads(suspended_threads); - ClassifyAllChunks(suspended_threads, ¶m->frontier); + ClassifyAllChunks(suspended_threads, ¶m->frontier, param->caller_tid, + param->caller_sp); ForEachChunk(CollectLeaksCb, ¶m->leaks); // Clean up for subsequent leak checks. This assumes we did not overwrite any // kIgnored tags. @@ -707,15 +713,15 @@ return false; } -static bool CheckForLeaks() { - if (&__lsan_is_turned_off && __lsan_is_turned_off()) - return false; +NOINLINE static bool CheckForLeaksBody(tid_t tid, uptr sp) { // Inside LockStuffAndStopTheWorld we can't run symbolizer, so we can't match // suppressions. However if a stack id was previously suppressed, it should be // suppressed in future checks as well. for (int i = 0;; ++i) { EnsureMainThreadIDIsCorrect(); CheckForLeaksParam param; + param.caller_tid = tid; + param.caller_sp = sp; LockStuffAndStopTheWorld(CheckForLeaksCallback, ¶m); if (!param.success) { Report("LeakSanitizer has encountered a fatal error.\n"); @@ -750,6 +756,17 @@ } } +static bool CheckForLeaks() { + if (&__lsan_is_turned_off && __lsan_is_turned_off()) + return false; + // Capture calling thread's stack pointer early, to avoid false negatives. + // Old frame with dead pointers might be overlapped by new frame inside + // CheckForLeaksBody which does not use bytes with pointers before the + // threads are suspended and stack pointers captured. + int i; + return CheckForLeaksBody(GetTid(), reinterpret_cast(&i)); +} + static bool has_reported_leaks = false; bool HasReportedLeaks() { return has_reported_leaks; }