This is the remaining patches from "Forward merging entries and other VM shenanigans" (specifically the vm_map_coalesce_entry part), with that one issue fixed. And here's a reproducer that fails with v1 and works now:
Sergey #define _GNU_SOURCE #include <stdio.h> #include <mach.h> #include <error.h> #include <errno.h> #include <unistd.h> #include <spawn.h> #include <sys/wait.h> int main () { error_t err; vm_offset_t offset; extern char **environ; pid_t pid; int *ptr; char *child_argv[] = { "vminfo", NULL, NULL }; asprintf (&child_argv[1], "%d", getpid ()); /* Allocate space for four pages. */ err = vm_allocate (mach_task_self (), &offset, vm_page_size * 4, 1); if (err) error (1, err, "vm_allocate space"); printf ("Allocated at %p\n", (void *) (offset + vm_page_size)); /* Deallocate them back! */ err = vm_deallocate (mach_task_self (), offset, vm_page_size * 4); if (err) error (1, err, "vm_deallocate space"); offset += vm_page_size; /* Allocate the two pages. */ err = vm_allocate (mach_task_self (), &offset, vm_page_size * 2, 0); if (err) error (1, err, "vm_allocate"); ptr = (int *) (offset + vm_page_size); /* Realize the object. */ *ptr = 1234; /* Deallocate the first page, and reallocate it with a different protection. */ err = vm_deallocate (mach_task_self (), offset, vm_page_size); if (err) error (1, err, "vm_deallocate page"); err = vm_map (mach_task_self (), &offset, vm_page_size, 0, 0, MACH_PORT_NULL, 0, 0, VM_PROT_ALL, VM_PROT_ALL, VM_INHERIT_COPY); if (err) error (1, err, "vm_map"); printf ("====== Before coalescing ======\n"); fflush (stdout); posix_spawn (&pid, "/bin/vminfo", NULL, NULL, child_argv, environ); wait (NULL); /* Coalesce the two entries back together. */ err = vm_protect (mach_task_self (), offset, vm_page_size, 0, VM_PROT_DEFAULT); if (err) error (1, err, "vm_protect (VM_PROT_DEFAULT)"); printf ("====== After coalescing ======\n"); fflush (stdout); posix_spawn (&pid, "/bin/vminfo", NULL, NULL, child_argv, environ); wait (NULL); /* Check whether the data is still there. */ printf ("%d\n", *(const int *) (offset + vm_page_size)); }