summaryrefslogtreecommitdiff
path: root/lib/lsan
diff options
context:
space:
mode:
authorFrancis Ricci <francisjricci@gmail.com>2017-04-19 21:11:08 +0000
committerFrancis Ricci <francisjricci@gmail.com>2017-04-19 21:11:08 +0000
commit60ceca6311c5611167f1b4639db19a83359c3674 (patch)
tree242411e011d5d7588217ca6bb7f845936798f048 /lib/lsan
parent223b56caae57fb066c4fb29b31528d27e01b843a (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.cc47
-rw-r--r--lib/lsan/lsan_common.h9
-rw-r--r--lib/lsan/lsan_common_mac.cc31
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 &region,
+ 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;
}
}