Commit aae707cd authored by Roland McGrath's avatar Roland McGrath Committed by Petr Hosek
Browse files

[lsan] Expose Frontier object to OS-specific LockStuffAndStopTheWorld callback

This is a small refactoring to prepare for porting LSan to Fuchsia.
On Fuchsia, the system supplies a unified API for suspending threads and
enumerating roots from OS-specific places like thread state and global data
ranges. So its LockStuffAndStopTheWorld implementation will make specific
callbacks for all the OS-specific root collection work before making the
common callback that includes the actual leak-checking logic.

Patch By: mcgrathr

Differential Revision: https://reviews.llvm.org/D72988
parent 5d87b5d2
Loading
Loading
Loading
Loading
+12 −20
Original line number Diff line number Diff line
@@ -443,25 +443,23 @@ void ProcessPC(Frontier *frontier) {
}

// Sets the appropriate tag on each chunk.
static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads) {
  // Holds the flood fill frontier.
  Frontier frontier;

  ForEachChunk(CollectIgnoredCb, &frontier);
  ProcessGlobalRegions(&frontier);
  ProcessThreads(suspended_threads, &frontier);
  ProcessRootRegions(&frontier);
  FloodFillTag(&frontier, kReachable);
static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads,
                              Frontier *frontier) {
  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 @@ static void PrintMatchedSuppressions() {
  Printf("%s\n\n", line);
}

struct CheckForLeaksParam {
  bool success;
  LeakReport leak_report;
};

static void ReportIfNotSuspended(ThreadContextBase *tctx, void *arg) {
  const InternalMmapVector<tid_t> &suspended_threads =
      *(const InternalMmapVector<tid_t> *)arg;
@@ -556,7 +549,7 @@ static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads,
  CHECK(param);
  CHECK(!param->success);
  ReportUnsuspendedThreads(suspended_threads);
  ClassifyAllChunks(suspended_threads);
  ClassifyAllChunks(suspended_threads, &param->frontier);
  ForEachChunk(CollectLeaksCb, &param->leak_report);
  // Clean up for subsequent leak checks. This assumes we did not overwrite any
  // kIgnored tags.
@@ -569,7 +562,6 @@ static bool CheckForLeaks() {
      return false;
  EnsureMainThreadIDIsCorrect();
  CheckForLeaksParam param;
  param.success = false;
  LockStuffAndStopTheWorld(CheckForLeaksCallback, &param);

  if (!param.success) {
+13 −1
Original line number Diff line number Diff line
@@ -126,12 +126,24 @@ struct RootRegion {
  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<RootRegion> const *GetRootRegions();
void ScanRootRegion(Frontier *frontier, RootRegion const &region,
                    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,
+2 −1
Original line number Diff line number Diff line
@@ -134,7 +134,8 @@ static int LockStuffAndStopTheWorldCallback(struct dl_phdr_info *info,
// 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, &param);
}
+2 −1
Original line number Diff line number Diff line
@@ -193,7 +193,8 @@ void ProcessPlatformSpecificAllocations(Frontier *frontier) {
// causes rare race conditions.
void HandleLeaks() {}

void LockStuffAndStopTheWorld(StopTheWorldCallback callback, void *argument) {
void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
                              CheckForLeaksParam *argument) {
  LockThreadRegistry();
  LockAllocator();
  StopTheWorld(callback, argument);