Skip to content

Account for committed memory when VMChunkCreate fails after ChunkInit starts - #320

Open
defmacro-jam wants to merge 1 commit into
Ravenbrook:masterfrom
defmacro-jam:branch/2026-10-25/chunk-create-commit-leak
Open

defmacro-jam wants to merge 1 commit into
Ravenbrook:masterfrom
defmacro-jam:branch/2026-10-25/chunk-create-commit-leak

Conversation

@defmacro-jam

Copy link
Copy Markdown

Fixes #319.

VMChunkCreate (code/arenavm.c) maps the chunk structure's grain with vmArenaMap, which adds it to arena->committed. When ChunkInit then failed, failChunkInit unmapped the grain with the raw VMUnmap, which does not subtract it. Each grow refused at the commit limit therefore left the arena over-counting committed memory, and mps_arena_destroy later failed AVER(arena->committed == VMMapped(VMArenaVM(vmArena))) at arenavm.c:799. failChunkInit now calls VMChunkFinish. That function unmaps the chunk's overhead through vmArenaUnmap, covering the chunk structure and any bit tables VMChunkInit mapped, and then finishes the VM.

That change also needs ChunkInit (code/tract.c) to stop calling the class's chunkFinish when ArenaFreeLandInsert fails. Otherwise that failure finishes the chunk twice. The old code already did that, so this fixes a second problem:

  • VMChunkFinish released the VM.
  • Then failChunkInit called VMUnmap and VMFinish on the stack copy of the same VM.
  • On Windows the second call is VirtualFree(MEM_DECOMMIT) on released address space, which I read as failing AVER(b != 0) at vmw3.c:225.
  • On POSIX it is a MAP_FIXED mapping and a second munmap over a range another thread may since have been given.

The client arena's chunkFinish does nothing and its clientChunkCreate has nothing to undo, so moving the responsibility to the caller changes nothing there.

Tested on macOS arm64 (16 KiB pages) with clang:

The ArenaFreeLandInsert failure path and Windows have not been run.

… starts.

VMChunkCreate maps the chunk structure's grain with vmArenaMap, which adds
it to arena->committed, but its failChunkInit path unmapped it with the raw
VMUnmap, which does not subtract it. A grow refused at the commit limit
therefore left the arena over-counting committed memory, and
mps_arena_destroy failed the check at arenavm.c:799. It now calls
VMChunkFinish, which unmaps the chunk's overhead through vmArenaUnmap and
finishes the VM.

ChunkInit no longer calls the arena class's chunkFinish when
ArenaFreeLandInsert fails. Its caller undoes the class's chunkInit, as it
must for every other failure; calling it in both places made the VM arena
unmap and finish the chunk's VM twice.

Fixes GitHub issue Ravenbrook#319 <Ravenbrook#319>.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

arenavm.c: VMChunkCreate leaks arena->committed when ChunkInit fails, then mps_arena_destroy asserts at arenavm.c:799

1 participant