diff --git a/code/arenavm.c b/code/arenavm.c index 50708e9563..ad3f3bc619 100644 --- a/code/arenavm.c +++ b/code/arenavm.c @@ -91,6 +91,7 @@ typedef struct VMArenaStruct { /* VM arena structure */ static void VMFree(Addr base, Size size, Pool pool); static Size VMPurgeSpare(Arena arena, Size size); static Size vmArenaUnmapSpare(Arena arena, Size size, Chunk filter); +static void VMChunkFinish(Chunk chunk); DECLARE_CLASS(Arena, VMArena, AbstractArena); static void VMCompact(Arena arena, Trace trace); static void pageDescUnmap(VMChunk vmChunk, Index basePI, Index limitPI); @@ -350,7 +351,13 @@ static Res VMChunkCreate(Chunk *chunkReturn, VMArena vmArena, Size size) return ResOK; failChunkInit: - VMUnmap(vm, VMBase(vm), chunkStructLimit); + /* ChunkInit leaves undoing VMChunkInit to its caller. VMChunkFinish + unmaps the chunk's overhead through vmArenaUnmap, so that + arena->committed stays equal to what is mapped, and finishes the VM. + See GitHub issue #319 . */ + VMChunkFinish(VMChunk2Chunk(vmChunk)); + return res; + failChunkMap: failChunkAlloc: failBootInit: diff --git a/code/tract.c b/code/tract.c index baa01ef611..aad755992a 100644 --- a/code/tract.c +++ b/code/tract.c @@ -238,9 +238,11 @@ Res ChunkInit(Chunk chunk, Arena arena, Addr base, Addr limit, Size reserved, return ResOK; failLandInsert: - Method(Arena, arena, chunkFinish)(chunk); /* .no-clean: No clean-ups needed past this point for boot, as we will - discard the chunk. */ + discard the chunk. The caller undoes the arena class's chunkInit, as + it must for every failure after it: calling chunkFinish here as well + made the VM arena unmap and finish the chunk's VM twice. See GitHub + issue #319 . */ failClassInit: failAllocTable: return res;