From 2fa5f5688d4e453acdf98accfdf40e2b14a983c5 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 12 Jun 2014 20:28:50 +0100 Subject: [PATCH] New function arenachunktreetraverse ensures that calls to chunkofaddr are reliably detected. Copied from Perforce Change: 186550 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 41 ++++++++++++++++++++++++++++++++++------- mps/code/arenacl.c | 5 +++-- mps/code/arenavm.c | 5 +++-- mps/code/mpm.h | 1 + mps/code/tree.c | 1 + mps/code/tree.h | 10 ++++++++++ 6 files changed, 52 insertions(+), 11 deletions(-) diff --git a/mps/code/arena.c b/mps/code/arena.c index 172ef9c671a..668cdab9e5c 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -147,8 +147,7 @@ Bool ArenaCheck(Arena arena) if (arena->primary != NULL) { CHECKD(Chunk, arena->primary); } - /* Can't use CHECKD_NOSIG because TreeEMPTY is NULL. */ - CHECKL(TreeCheck(ArenaChunkTree(arena))); + /* Can't check chunkTree, it might be bad during ArenaChunkTreeTraverse. */ /* nothing to check for chunkSerial */ CHECKL(LocusCheck(arena)); @@ -570,8 +569,7 @@ Res ArenaDescribeTracts(Arena arena, mps_lib_FILE *stream, Count depth) cl.stream = stream; cl.res = ResOK; - (void)TreeTraverse(ArenaChunkTree(arena), ChunkCompare, ChunkKey, - arenaDescribeTractsInChunk, &cl, depth); + (void)ArenaChunkTreeTraverse(arena, arenaDescribeTractsInChunk, &cl, depth); return cl.res; } @@ -635,6 +633,34 @@ Res ControlDescribe(Arena arena, mps_lib_FILE *stream, Count depth) } +/* ArenaChunkTreeTraverse -- call visitor for each chunk */ + +Bool ArenaChunkTreeTraverse(Arena arena, TreeVisitor visitor, + void *closureP, Size closureS) +{ + Bool b; + Tree tree; + + AVERT(Arena, arena); + AVER(FUNCHECK(visitor)); + /* closureP and closureS are arbitrary. */ + + /* During TreeTraverse, the tree is invalid, so temporarily set + * arena->chunkTree to an invalid value, to ensure that if someone + * calls ChunkOfAddr while we are iterating this results in an + * assertion failure (in checking varieties) or a segfault, rather + * than a silent failure to find the chunk. + */ + + tree = ArenaChunkTree(arena); + arena->chunkTree = TreeBAD; + b = TreeTraverse(tree, ChunkCompare, ChunkKey, visitor, closureP, closureS); + arena->chunkTree = tree; + + return b; +} + + /* ArenaChunkInsert -- insert chunk into arena's chunk tree */ void ArenaChunkInsert(Arena arena, Tree tree) { @@ -681,6 +707,7 @@ static Bool arenaAllocPageInChunk(Tree tree, void *closureP, Size closureS) AVER(closureP != NULL); cl = closureP; AVER(cl->arena == ChunkArena(chunk)); + AVER(closureS == UNUSED_SIZE); UNUSED(closureS); /* Already searched in arenaAllocPage. */ @@ -725,12 +752,12 @@ static Res arenaAllocPage(Addr *baseReturn, Arena arena, Pool pool) /* Favour the primary chunk, because pages allocated this way aren't currently freed, and we don't want to prevent chunks being destroyed. */ /* TODO: Consider how the ArenaCBSBlockPool might free pages. */ - if (!arenaAllocPageInChunk(&arena->primary->chunkTree, &closure, 0)) + if (!arenaAllocPageInChunk(&arena->primary->chunkTree, &closure, UNUSED_SIZE)) goto found; closure.avoid = arena->primary; - if (!TreeTraverse(ArenaChunkTree(arena), ChunkCompare, ChunkKey, - arenaAllocPageInChunk, &closure, 0)) + if (!ArenaChunkTreeTraverse(arena, arenaAllocPageInChunk, + &closure, UNUSED_SIZE)) goto found; AVER(closure.res != ResOK); diff --git a/mps/code/arenacl.c b/mps/code/arenacl.c index cb4d9865ae3..a6d7f79c65c 100644 --- a/mps/code/arenacl.c +++ b/mps/code/arenacl.c @@ -349,6 +349,7 @@ static Bool clientArenaReservedVisitor(Tree tree, void *closureP, Size closureS) AVERT(Chunk, chunk); AVER(closureP != 0); size = closureP; + AVER(closureS == UNUSED_SIZE); UNUSED(closureS); *size += ChunkSize(chunk); @@ -361,8 +362,8 @@ static Size ClientArenaReserved(Arena arena) AVERT(Arena, arena); - (void)TreeTraverse(ArenaChunkTree(arena), ChunkCompare, ChunkKey, - clientArenaReservedVisitor, &size, 0); + (void)ArenaChunkTreeTraverse(arena, clientArenaReservedVisitor, + &size, UNUSED_SIZE); return size; } diff --git a/mps/code/arenavm.c b/mps/code/arenavm.c index 33d1579e82b..07a1d492aa2 100644 --- a/mps/code/arenavm.c +++ b/mps/code/arenavm.c @@ -642,6 +642,7 @@ static Bool vmArenaReservedVisitor(Tree tree, void *closureP, Size closureS) AVERT(Chunk, chunk); AVER(closureP != 0); size = closureP; + AVER(closureS == UNUSED_SIZE); UNUSED(closureS); *size += VMReserved(Chunk2VMChunk(chunk)->vm); @@ -655,8 +656,8 @@ static Size VMArenaReserved(Arena arena) AVERT(Arena, arena); - (void)TreeTraverse(ArenaChunkTree(arena), ChunkCompare, ChunkKey, - vmArenaReservedVisitor, &size, 0); + (void)ArenaChunkTreeTraverse(arena, vmArenaReservedVisitor, + &size, UNUSED_SIZE); return size; } diff --git a/mps/code/mpm.h b/mps/code/mpm.h index ccec0aff383..a0d5f858a10 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -557,6 +557,7 @@ extern Res ArenaStartCollect(Globals globals, int why); extern Res ArenaCollect(Globals globals, int why); extern Bool ArenaHasAddr(Arena arena, Addr addr); extern Res ArenaAddrObject(Addr *pReturn, Arena arena, Addr addr); +extern Bool ArenaChunkTreeTraverse(Arena arena, TreeVisitor visitor, void *closureP, Size closureS); extern void ArenaChunkInsert(Arena arena, Tree tree); extern void ArenaSetEmergency(Arena arena, Bool emergency); diff --git a/mps/code/tree.c b/mps/code/tree.c index e6dd902f3fd..ff77fde15c4 100644 --- a/mps/code/tree.c +++ b/mps/code/tree.c @@ -24,6 +24,7 @@ SRCID(tree, "$Id$"); Bool TreeCheck(Tree tree) { if (tree != TreeEMPTY) { + CHECKL(tree != TreeBAD); CHECKL(tree != NULL); CHECKL(tree->left == TreeEMPTY || tree->left != NULL); CHECKL(tree->right == TreeEMPTY || tree->right != NULL); diff --git a/mps/code/tree.h b/mps/code/tree.h index 4ac1a82eaaf..5c0ea05ac51 100644 --- a/mps/code/tree.h +++ b/mps/code/tree.h @@ -64,6 +64,16 @@ typedef TreeKey (*TreeKeyMethod)(Tree tree); #define TreeEMPTY ((Tree)0) + +/* TreeBAD -- an invalid tree + * + * TreeBAD is a value that's not equal to any tree (not even to + * the empty tree). + */ + +#define TreeBAD ((Tree)7) + + extern Bool TreeCheck(Tree tree); extern Bool TreeCheckLeaf(Tree tree); extern Count TreeDebugCount(Tree tree, TreeCompare compare, TreeKeyMethod key);