-
Notifications
You must be signed in to change notification settings - Fork 15k
[sanitizer-common] Improve diagnostic when ASAN fails to allocate shadow #158378
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
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
Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be notified. If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers. If you have further questions, they may be answered by the LLVM GitHub User Guide. You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums. |
@llvm/pr-subscribers-compiler-rt-sanitizer Author: Andrew Haberlandt (ndrewh) ChangesSometimes 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:
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);
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@ndrewh Congratulations on having your first Pull Request (PR) merged into the LLVM Project! Your changes will be combined with recent changes from other authors, then tested by our build bots. If there is a problem with a build, you may receive a report in an email or a comment on this PR. Please check whether problems have been caused by your change specifically, as the builds can include changes from many authors. It is not uncommon for your change to be included in a build that fails due to someone else's changes, or infrastructure issues. How to do this, and the rest of the post-merge process, is covered in detail here. If your change does cause a problem, it may be reverted, or you can revert it yourself. This is a normal part of LLVM development. You can fix your changes and open a new PR to merge them again. If you don't get any reports, no action is required from you. Your changes are working as expected, well done! |
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/174/builds/24521 Here is the relevant piece of the build log for the reference
|
failure looks like a dupe of #156257 |
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