[compiler-rt] [sanitizer-common] Improve diagnostic when ASAN fails to allocate shadow (PR #158378)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 12 15:12:38 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-compiler-rt-sanitizer
Author: Andrew Haberlandt (ndrewh)
<details>
<summary>Changes</summary>
Sometimes we are unable to find a sufficiently large gap to allocate the dynamic ASAN shadow.
If a gap is not found, we will now output a (consolidated) memory map to show the user what regions were unavailable and how much memory we need.
rdar://159142896
---
Full diff: https://github.com/llvm/llvm-project/pull/158378.diff
1 Files Affected:
- (modified) compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp (+79-17)
``````````diff
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp
index d4811ff4ed217..c4a6bf5bcbbee 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp
@@ -22,6 +22,11 @@
# endif
# include <stdio.h>
+// Start searching for available memory region past PAGEZERO, which is
+// 4KB on 32-bit and 4GB on 64-bit.
+# define GAP_SEARCH_START_ADDRESS \
+ ((SANITIZER_WORDSIZE == 32) ? 0x000000001000 : 0x000100000000)
+
# include "sanitizer_common.h"
# include "sanitizer_file.h"
# include "sanitizer_flags.h"
@@ -58,6 +63,7 @@ extern char ***_NSGetArgv(void);
# include <dlfcn.h> // for dladdr()
# include <errno.h>
# include <fcntl.h>
+# include <inttypes.h>
# include <libkern/OSAtomic.h>
# include <mach-o/dyld.h>
# include <mach/mach.h>
@@ -1106,6 +1112,67 @@ static void StripEnv() {
}
#endif // SANITIZER_GO
+// Prints out a consolidated memory map: contiguous regions
+// are merged together.
+static void PrintVmmap() {
+ const mach_vm_address_t max_vm_address = GetMaxVirtualAddress() + 1;
+ mach_vm_address_t address = GAP_SEARCH_START_ADDRESS;
+ kern_return_t kr = KERN_SUCCESS;
+
+ Report("Memory map:\n");
+ mach_vm_address_t last = 0;
+ mach_vm_address_t lastsz = 0;
+
+ while (1) {
+ mach_vm_size_t vmsize = 0;
+ natural_t depth = 0;
+ vm_region_submap_short_info_data_64_t vminfo;
+ mach_msg_type_number_t count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
+ kr = mach_vm_region_recurse(mach_task_self(), &address, &vmsize, &depth,
+ (vm_region_info_t)&vminfo, &count);
+
+ if (kr == KERN_DENIED) {
+ Report(
+ "ERROR: mach_vm_region_recurse got KERN_DENIED when printing memory "
+ "map.\n");
+ Report(
+ "HINT: Check whether mach_vm_region_recurse is allowed by "
+ "sandbox.\n");
+ }
+
+ if (kr == KERN_SUCCESS && address < max_vm_address) {
+ if (last + lastsz == address) {
+ // This region is contiguous with the last; merge together.
+ lastsz += vmsize;
+ } else {
+ if (lastsz)
+ Printf("|| `[%p, %p]` || size=0x%016" PRIx64 " ||\n", last,
+ last + lastsz, lastsz);
+
+ last = address;
+ lastsz = vmsize;
+ }
+ address += vmsize;
+ } else {
+ // We've reached the end of the memory map. Print the last remaining
+ // region, if there is one.
+ if (lastsz)
+ Printf("|| `[%p, %p]` || size=0x%016" PRIx64 " ||\n", last,
+ last + lastsz, lastsz);
+
+ break;
+ }
+ }
+}
+
+static void ReportShadowAllocFail(uptr shadow_size_bytes, uptr alignment) {
+ Report(
+ "FATAL: Failed to allocate shadow memory. Tried to allocate %p bytes "
+ "(alignment=%p).\n",
+ shadow_size_bytes, alignment);
+ PrintVmmap();
+}
+
char **GetArgv() {
return *_NSGetArgv();
}
@@ -1213,10 +1280,11 @@ uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
if (new_max_vm < max_occupied_addr) {
Report("Unable to find a memory range for dynamic shadow.\n");
Report(
- "space_size = %p, largest_gap_found = %p, max_occupied_addr = %p, "
- "new_max_vm = %p\n",
- (void *)space_size, (void *)largest_gap_found,
- (void *)max_occupied_addr, (void *)new_max_vm);
+ "\tspace_size = %p\n\tlargest_gap_found = %p\n\tmax_occupied_addr "
+ "= %p\n\tnew_max_vm = %p\n",
+ (void*)space_size, (void*)largest_gap_found, (void*)max_occupied_addr,
+ (void*)new_max_vm);
+ ReportShadowAllocFail(shadow_size_bytes, alignment);
CHECK(0 && "cannot place shadow");
}
RestrictMemoryToMaxAddress(new_max_vm);
@@ -1227,6 +1295,7 @@ uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
nullptr, nullptr);
if (shadow_start == 0) {
Report("Unable to find a memory range after restricting VM.\n");
+ ReportShadowAllocFail(shadow_size_bytes, alignment);
CHECK(0 && "cannot place shadow after restricting vm");
}
}
@@ -1242,26 +1311,19 @@ uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
}
uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
- uptr *largest_gap_found,
- uptr *max_occupied_addr) {
- typedef vm_region_submap_short_info_data_64_t RegionInfo;
- enum { kRegionInfoSize = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 };
- // Start searching for available memory region past PAGEZERO, which is
- // 4KB on 32-bit and 4GB on 64-bit.
- mach_vm_address_t start_address =
- (SANITIZER_WORDSIZE == 32) ? 0x000000001000 : 0x000100000000;
-
+ uptr* largest_gap_found,
+ uptr* max_occupied_addr) {
const mach_vm_address_t max_vm_address = GetMaxVirtualAddress() + 1;
- mach_vm_address_t address = start_address;
- mach_vm_address_t free_begin = start_address;
+ mach_vm_address_t address = GAP_SEARCH_START_ADDRESS;
+ mach_vm_address_t free_begin = GAP_SEARCH_START_ADDRESS;
kern_return_t kr = KERN_SUCCESS;
if (largest_gap_found) *largest_gap_found = 0;
if (max_occupied_addr) *max_occupied_addr = 0;
while (kr == KERN_SUCCESS) {
mach_vm_size_t vmsize = 0;
natural_t depth = 0;
- RegionInfo vminfo;
- mach_msg_type_number_t count = kRegionInfoSize;
+ vm_region_submap_short_info_data_64_t vminfo;
+ mach_msg_type_number_t count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
kr = mach_vm_region_recurse(mach_task_self(), &address, &vmsize, &depth,
(vm_region_info_t)&vminfo, &count);
``````````
</details>
https://github.com/llvm/llvm-project/pull/158378
More information about the llvm-commits
mailing list