diff options
author | Francis Ricci <francisjricci@gmail.com> | 2017-04-19 21:11:08 +0000 |
---|---|---|
committer | Francis Ricci <francisjricci@gmail.com> | 2017-04-19 21:11:08 +0000 |
commit | 60ceca6311c5611167f1b4639db19a83359c3674 (patch) | |
tree | 242411e011d5d7588217ca6bb7f845936798f048 /lib/lsan | |
parent | 223b56caae57fb066c4fb29b31528d27e01b843a (diff) |
Make sure to scan mmap'd memory regions for root pointers on OS X
Summary:
In the general case, we only need to check for root regions inside
the memory map returned by procmaps. However, on Darwin,
we also need to check inside mmap'd regions, which aren't returned
in the list of modules we get from procmaps.
This patch refactors memory region scanning on darwin to reduce
code duplication with the kernel alloc once page scan.
Reviewers: kubamracek, alekseyshl
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D32190
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@300760 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/lsan')
-rw-r--r-- | lib/lsan/lsan_common.cc | 47 | ||||
-rw-r--r-- | lib/lsan/lsan_common.h | 9 | ||||
-rw-r--r-- | lib/lsan/lsan_common_mac.cc | 31 |
3 files changed, 58 insertions, 29 deletions
diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index 9d65918aa..d3385df7f 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -83,13 +83,10 @@ static SuppressionContext *GetSuppressionContext() { return suppression_ctx; } -struct RootRegion { - const void *begin; - uptr size; -}; - InternalMmapVector<RootRegion> *root_regions; +InternalMmapVector<RootRegion> const *GetRootRegions() { return root_regions; } + void InitializeRootRegions() { CHECK(!root_regions); ALIGNED(64) static char placeholder[sizeof(InternalMmapVector<RootRegion>)]; @@ -291,23 +288,29 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads, } } -static void ProcessRootRegion(Frontier *frontier, uptr root_begin, - uptr root_end) { - MemoryMappingLayout proc_maps(/*cache_enabled*/true); +void ScanRootRegion(Frontier *frontier, RootRegion const &root_region, + uptr region_begin, uptr region_end, uptr prot) { + uptr intersection_begin = Max(root_region.begin, region_begin); + uptr intersection_end = Min(region_end, root_region.begin + root_region.size); + 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_region.begin, root_region.begin + root_region.size, + region_begin, region_end, + is_readable ? "readable" : "unreadable"); + if (is_readable) + ScanRangeForPointers(intersection_begin, intersection_end, frontier, "ROOT", + kReachable); +} + +static void ProcessRootRegion(Frontier *frontier, + RootRegion const &root_region) { + MemoryMappingLayout proc_maps(/*cache_enabled*/ true); uptr begin, end, prot; 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_region, begin, end, prot); } } @@ -316,9 +319,7 @@ static void ProcessRootRegions(Frontier *frontier) { if (!flags()->use_root_regions) return; CHECK(root_regions); for (uptr i = 0; i < root_regions->size(); i++) { - RootRegion region = (*root_regions)[i]; - uptr begin_addr = reinterpret_cast<uptr>(region.begin); - ProcessRootRegion(frontier, begin_addr, begin_addr + region.size); + ProcessRootRegion(frontier, (*root_regions)[i]); } } @@ -775,7 +776,7 @@ void __lsan_register_root_region(const void *begin, uptr size) { #if CAN_SANITIZE_LEAKS BlockingMutexLock l(&global_mutex); CHECK(root_regions); - RootRegion region = {begin, size}; + RootRegion region = {reinterpret_cast<uptr>(begin), size}; root_regions->push_back(region); VReport(1, "Registered root region at %p of size %llu\n", begin, size); #endif // CAN_SANITIZE_LEAKS @@ -789,7 +790,7 @@ void __lsan_unregister_root_region(const void *begin, uptr size) { bool removed = false; for (uptr i = 0; i < root_regions->size(); i++) { RootRegion region = (*root_regions)[i]; - if (region.begin == begin && region.size == size) { + if (region.begin == reinterpret_cast<uptr>(begin) && region.size == size) { removed = true; uptr last_index = root_regions->size() - 1; (*root_regions)[i] = (*root_regions)[last_index]; diff --git a/lib/lsan/lsan_common.h b/lib/lsan/lsan_common.h index 88d5f1ca7..121b9c082 100644 --- a/lib/lsan/lsan_common.h +++ b/lib/lsan/lsan_common.h @@ -118,6 +118,15 @@ typedef InternalMmapVector<uptr> Frontier; void InitializePlatformSpecificModules(); void ProcessGlobalRegions(Frontier *frontier); void ProcessPlatformSpecificAllocations(Frontier *frontier); + +struct RootRegion { + uptr begin; + uptr size; +}; + +InternalMmapVector<RootRegion> const *GetRootRegions(); +void ScanRootRegion(Frontier *frontier, RootRegion const ®ion, + uptr region_begin, uptr region_end, uptr prot); // Run stoptheworld while holding any platform-specific locks. void DoStopTheWorld(StopTheWorldCallback callback, void* argument); diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc index a158b6512..a9adcdfff 100644 --- a/lib/lsan/lsan_common_mac.cc +++ b/lib/lsan/lsan_common_mac.cc @@ -117,8 +117,6 @@ void ProcessGlobalRegions(Frontier *frontier) { } } -// libxpc stashes some pointers in the Kernel Alloc Once page, -// make sure not to report those as leaks. void ProcessPlatformSpecificAllocations(Frontier *frontier) { mach_port_name_t port; if (task_for_pid(mach_task_self(), internal_getpid(), &port) @@ -132,16 +130,37 @@ void ProcessPlatformSpecificAllocations(Frontier *frontier) { kern_return_t err = KERN_SUCCESS; mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64; + InternalMmapVector<RootRegion> const *root_regions = GetRootRegions(); + while (err == KERN_SUCCESS) { struct vm_region_submap_info_64 info; err = vm_region_recurse_64(port, &address, &size, &depth, (vm_region_info_t)&info, &count); + + uptr end_address = address + size; + + // libxpc stashes some pointers in the Kernel Alloc Once page, + // make sure not to report those as leaks. if (info.user_tag == VM_MEMORY_OS_ALLOC_ONCE) { - ScanRangeForPointers(address, address + size, frontier, - "GLOBAL", kReachable); - return; + ScanRangeForPointers(address, end_address, frontier, "GLOBAL", + kReachable); } - address += size; + + // This additional root region scan is required on Darwin in order to + // detect root regions contained within mmap'd memory regions, because + // the Darwin implementation of sanitizer_procmaps traverses images + // as loaded by dyld, and not the complete set of all memory regions. + // + // TODO(fjricci) - remove this once sanitizer_procmaps_mac has the same + // behavior as sanitizer_procmaps_linux and traverses all memory regions + if (flags()->use_root_regions) { + for (uptr i = 0; i < root_regions->size(); i++) { + ScanRootRegion(frontier, (*root_regions)[i], address, end_address, + info.protection); + } + } + + address = end_address; } } |