Index: lib/lsan/lsan_common.h =================================================================== --- lib/lsan/lsan_common.h +++ lib/lsan/lsan_common.h @@ -118,6 +118,10 @@ void InitializePlatformSpecificModules(); void ProcessGlobalRegions(Frontier *frontier); void ProcessPlatformSpecificAllocations(Frontier *frontier); +void ProcessPlatformSpecificRootRegion(Frontier *frontier, uptr root_begin, + uptr root_end); +void ScanRootRegion(Frontier *frontier, uptr root_begin, uptr root_end, + uptr region_begin, uptr region_end, uptr prot); // Run stoptheworld while holding any platform-specific locks. void DoStopTheWorld(StopTheWorldCallback callback, void* argument); Index: lib/lsan/lsan_common.cc =================================================================== --- lib/lsan/lsan_common.cc +++ lib/lsan/lsan_common.cc @@ -291,6 +291,20 @@ } } +void ScanRootRegion(Frontier *frontier, uptr root_begin, uptr root_end, + uptr region_begin, uptr region_end, uptr prot) { + uptr intersection_begin = Max(root_begin, region_begin); + uptr intersection_end = Min(region_end, root_end); + if (intersection_begin >= intersection_end) return; + bool is_readable = prot & MemoryMappingLayout::kProtectionRead; + LOG_POINTERS("Root region %p-%p intersects with mapped region %p-%p (%s)\n", + root_begin, root_end, region_begin, region_end, + is_readable ? "readable" : "unreadable"); + if (is_readable) + ScanRangeForPointers(intersection_begin, intersection_end, frontier, + "ROOT", kReachable); +} + static void ProcessRootRegion(Frontier *frontier, uptr root_begin, uptr root_end) { MemoryMappingLayout proc_maps(/*cache_enabled*/true); @@ -298,17 +312,9 @@ while (proc_maps.Next(&begin, &end, /*offset*/ nullptr, /*filename*/ nullptr, /*filename_size*/ 0, &prot)) { - uptr intersection_begin = Max(root_begin, begin); - uptr intersection_end = Min(end, root_end); - if (intersection_begin >= intersection_end) continue; - bool is_readable = prot & MemoryMappingLayout::kProtectionRead; - LOG_POINTERS("Root region %p-%p intersects with mapped region %p-%p (%s)\n", - root_begin, root_end, begin, end, - is_readable ? "readable" : "unreadable"); - if (is_readable) - ScanRangeForPointers(intersection_begin, intersection_end, frontier, - "ROOT", kReachable); + ScanRootRegion(frontier, root_begin, root_end, begin, end, prot); } + ProcessPlatformSpecificRootRegion(frontier, root_begin, root_end); } // Scans root regions for heap pointers. Index: lib/lsan/lsan_common_linux.cc =================================================================== --- lib/lsan/lsan_common_linux.cc +++ lib/lsan/lsan_common_linux.cc @@ -91,6 +91,9 @@ LoadedModule *GetLinker() { return linker; } +void ProcessPlatformSpecificRootRegion(Frontier *frontier, uptr root_begin, + uptr root_end) {} + void ProcessPlatformSpecificAllocations(Frontier *frontier) {} struct DoStopTheWorldParam { Index: lib/lsan/lsan_common_mac.cc =================================================================== --- lib/lsan/lsan_common_mac.cc +++ lib/lsan/lsan_common_mac.cc @@ -117,9 +117,24 @@ } } -// libxpc stashes some pointers in the Kernel Alloc Once page, -// make sure not to report those as leaks. -void ProcessPlatformSpecificAllocations(Frontier *frontier) { +typedef void (*MemoryRegionCallback)(Frontier *frontier, uptr address, + uptr size, vm_region_submap_info_64 &info, + void *arg); + +typedef struct { + uptr root_begin; + uptr root_end; +} root_region_arg_t; + +void ScanRootRegionCb(Frontier *frontier, uptr address, uptr size, + vm_region_submap_info_64 &info, void *arg) { + root_region_arg_t *data = reinterpret_cast(arg); + ScanRootRegion(frontier, data->root_begin, data->root_end, address, + address+size, info.protection); +} + +static void ProcessMemoryRegion(Frontier *frontier, + MemoryRegionCallback callback, void *arg) { mach_port_name_t port; if (task_for_pid(mach_task_self(), internal_getpid(), &port) != KERN_SUCCESS) { @@ -136,15 +151,33 @@ struct vm_region_submap_info_64 info; err = vm_region_recurse_64(port, &address, &size, &depth, (vm_region_info_t)&info, &count); - if (info.user_tag == VM_MEMORY_OS_ALLOC_ONCE) { - ScanRangeForPointers(address, address + size, frontier, - "GLOBAL", kReachable); - return; - } + callback(frontier, address, size, info, arg); address += size; } } +void ProcessPlatformSpecificRootRegion(Frontier *frontier, uptr root_begin, + uptr root_end) { + root_region_arg_t arg; + arg.root_begin = root_begin; + arg.root_end = root_end; + ProcessMemoryRegion(frontier, ScanRootRegionCb, &arg); +} + +void AllocOncePageCb(Frontier *frontier, uptr address, uptr size, + vm_region_submap_info_64 &info, void *arg) { + if (info.user_tag == VM_MEMORY_OS_ALLOC_ONCE) { + ScanRangeForPointers(address, address + size, frontier, + "GLOBAL", kReachable); + } +} + +// libxpc stashes some pointers in the Kernel Alloc Once page, +// make sure not to report those as leaks. +void ProcessPlatformSpecificAllocations(Frontier *frontier) { + ProcessMemoryRegion(frontier, AllocOncePageCb, nullptr); +} + void DoStopTheWorld(StopTheWorldCallback callback, void *argument) { StopTheWorld(callback, argument); }