[compiler-rt] [sanitizer-common][Darwin] gracefully handle mach_vm_region_recurse error (PR #194436)

via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 27 11:54:47 PDT 2026


https://github.com/SharonXSharon created https://github.com/llvm/llvm-project/pull/194436

`[sanitizer-common][Darwin] Improve mach_vm_region_recurse error handling (#158670)`) added specific error messages for non-`KERN_SUCCESS` return codes from `mach_vm_region_recurse` in `FindAvailableMemoryRange`. It also changed the behavior of the `KERN_DENIED` case to call `Die()` and the catch-all `else` case to call `break`, both of which prevent the gap-checking code from running and cause a fatal crash instead of attempting shadow placement.

On iOS App extensions (e.g. widgets), the sandbox can block `mach_vm_region_recurse`, returning `KERN_DENIED` or other error codes during early memprof initialization, causing app extension crash. 

The patch keeps the newly added error messages added by #158670, but instead of `Die()` or `break`, set `address = max_vm_address` , the same as how the code is handling `KERN_INVALID_ADDRESS`, so the code will attempt to check the gap and let the subsequent code handle if the gap is useable. 

>From fbe4e1f30a84043a2697f27cc59e1decc9c73c0c Mon Sep 17 00:00:00 2001
From: Sharon Xu <sharonxu at fb.com>
Date: Mon, 27 Apr 2026 11:09:24 -0700
Subject: [PATCH] [sanitizer-common][Darwin] gracefully handle
 mach_vm_region_recurse error

8fb02fae9957 (`[sanitizer-common][Darwin] Improve mach_vm_region_recurse
error handling (#158670)`) added specific error messages for
non-`KERN_SUCCESS` return codes from `mach_vm_region_recurse` in
`FindAvailableMemoryRange`. However, the `KERN_DENIED` case calls
`Die()` and the catch-all `else` case calls `break`, both of which
prevent the gap-checking code from running and cause a fatal crash
instead of attempting shadow placement.

On iOS/macOS app extensions (e.g. widgets), the sandbox can block
`mach_vm_region_recurse`, returning `KERN_DENIED` or other error codes
during early memprof initialization. This causes a `SIGABRT` crash
during `libSystem_initializer`.

Keep the error messages added by that commit, but instead of `Die()` or
`break`, set `address = max_vm_address` so the remaining address space
is treated as free and the gap-checking code can still attempt to place
the shadow.
---
 compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp     | 10 ++++++----
 .../TestCases/Darwin/sandbox-vm-region-recurse.cpp     |  5 +++--
 2 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp
index 6fafc04f557b4..ee67fab73f3df 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp
@@ -1363,14 +1363,16 @@ uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
     } else if (kr == KERN_DENIED) {
       Report("ERROR: Unable to find a memory range for dynamic shadow.\n");
       Report("HINT: Ensure mach_vm_region_recurse is allowed under sandbox.\n");
-      Die();
+      address = max_vm_address;
+
+      // We will break after this iteration since kr != KERN_SUCCESS
     } else {
       Report(
           "WARNING: mach_vm_region_recurse returned unexpected code %d (%s)\n",
           kr, mach_error_string(kr));
-      DCHECK(false && "mach_vm_region_recurse returned unexpected code");
-      break;  // address is not valid unless KERN_SUCCESS, therefore we must not
-              // use it.
+      address = max_vm_address;
+
+      // We will break after this iteration since kr != KERN_SUCCESS
     }
 
     if (free_begin != address) {
diff --git a/compiler-rt/test/asan/TestCases/Darwin/sandbox-vm-region-recurse.cpp b/compiler-rt/test/asan/TestCases/Darwin/sandbox-vm-region-recurse.cpp
index c496d822a7fb8..58ee270361b19 100644
--- a/compiler-rt/test/asan/TestCases/Darwin/sandbox-vm-region-recurse.cpp
+++ b/compiler-rt/test/asan/TestCases/Darwin/sandbox-vm-region-recurse.cpp
@@ -1,4 +1,5 @@
-// Check that if mach_vm_region_recurse is disallowed by sandbox, we report a message saying so.
+// Check that if mach_vm_region_recurse is disallowed by sandbox, we report a
+// hint but still gracefully proceed with shadow placement and detect errors.
 
 // RUN: %clangxx_asan -O0 %s -o %t
 // RUN: not %run sandbox-exec -p '(version 1)(allow default)(deny syscall-mig (kernel-mig-routine mach_vm_region_recurse))' %t 2>&1 | FileCheck --check-prefix=CHECK-DENY %s
@@ -20,7 +21,6 @@ int main() {
   free(x);
   return x[5];
   // CHECK-ALLOW: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}}
-  // CHECK-DENY-NOT: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}}
   // CHECK-ALLOW: {{READ of size 1 at 0x.* thread T0}}
   // CHECK-ALLOW: {{    #0 0x.* in main}}
   // CHECK-ALLOW: {{freed by thread T0 here:}}
@@ -30,4 +30,5 @@ int main() {
   // CHECK-ALLOW: {{    #0 0x.* in malloc}}
   // CHECK-ALLOW: {{    #1 0x.* in main}}
   // CHECK-DENY: {{.*HINT: Ensure mach_vm_region_recurse is allowed under sandbox}}
+  // CHECK-DENY: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}}
 }



More information about the llvm-commits mailing list