[NFC][sanitizer] Avoid O(N^2) algorithm
authorVitaly Buka <vitalybuka@google.com>
Wed, 31 May 2023 05:58:23 +0000 (22:58 -0700)
committerVitaly Buka <vitalybuka@google.com>
Fri, 2 Jun 2023 21:32:03 +0000 (14:32 -0700)
Usually root_regions size is small so unlikey
this change will provide a noticable difference.

However it's easy to make sure that even with
large number of root_regions it works reasonably
fast.

Differential Revision: https://reviews.llvm.org/D151781

compiler-rt/lib/lsan/lsan_common.cpp
compiler-rt/lib/lsan/lsan_common.h

index 2a6b53d..8902d93 100644 (file)
@@ -525,30 +525,19 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
 
 bool HasRootRegions() { return !root_regions.empty(); }
 
-static void ScanRootRegion(Frontier *frontier, const Region &root_region,
-                           uptr region_begin, uptr region_end,
-                           bool is_readable) {
-  uptr intersection_begin = Max(root_region.begin, region_begin);
-  uptr intersection_end = Min(region_end, root_region.end);
-  if (intersection_begin >= intersection_end)
-    return;
-  LOG_POINTERS("Root region %p-%p intersects with mapped region %p-%p (%s)\n",
-               (void *)root_region.begin, (void *)root_region.end,
-               (void *)region_begin, (void *)region_end,
-               is_readable ? "readable" : "unreadable");
-  if (is_readable)
-    ScanRangeForPointers(intersection_begin, intersection_end, frontier, "ROOT",
-                         kReachable);
-}
-
 void ScanRootRegions(Frontier *frontier,
                      const InternalMmapVectorNoCtor<Region> &mapped_regions) {
-  if (!flags()->use_root_regions || mapped_regions.empty())
+  if (!flags()->use_root_regions)
     return;
 
-  for (const auto &m : mapped_regions)
-    for (const auto &r : root_regions)
-      ScanRootRegion(frontier, r, m.begin, m.end, true);
+  InternalMmapVector<Region> intersection;
+  Intersect(mapped_regions, root_regions, intersection);
+
+  for (const Region &r : intersection) {
+    LOG_POINTERS("Root region intersects with mapped region at %p-%p\n",
+                 (void *)r.begin, (void *)r.end);
+    ScanRangeForPointers(r.begin, r.end, frontier, "ROOT", kReachable);
+  }
 }
 
 // Scans root regions for heap pointers.
index 0ef74bb..9320446 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "sanitizer_common/sanitizer_allocator.h"
 #include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_common_range.h"
 #include "sanitizer_common/sanitizer_internal_defs.h"
 #include "sanitizer_common/sanitizer_platform.h"
 #include "sanitizer_common/sanitizer_stackdepot.h"
@@ -79,11 +80,6 @@ enum IgnoreObjectResult {
   kIgnoreObjectInvalid
 };
 
-struct Range {
-  uptr begin;
-  uptr end;
-};
-
 //// --------------------------------------------------------------------------
 //// Poisoning prototypes.
 //// --------------------------------------------------------------------------
@@ -239,11 +235,6 @@ void InitializePlatformSpecificModules();
 void ProcessGlobalRegions(Frontier *frontier);
 void ProcessPlatformSpecificAllocations(Frontier *frontier);
 
-struct Region {
-  uptr begin;
-  uptr end;
-};
-
 // 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
@@ -256,6 +247,8 @@ struct CheckForLeaksParam {
   bool success = false;
 };
 
+using Region = Range;
+
 bool HasRootRegions();
 void ScanRootRegions(Frontier *frontier,
                      const InternalMmapVectorNoCtor<Region> &region);