mirror of
https://github.com/intel/llvm.git
synced 2026-01-22 07:01:03 +08:00
[sanitizer-common] Improve diagnostic when ASAN fails to allocate shadow (#158378)
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
This commit is contained in:
committed by
GitHub
parent
9b95e10d5e
commit
1fea3c507c
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user