It was difficult to track down the memory corruption bug fixed by the previous patch (PR jit/68446). The following patch attempts to make it easier to find that kind of thing by adding "poisoning" code:
(A) when memory blocks are returned to the memory_block_pool's free list (e.g. by an obstack), fill the content with a garbage value. (B) When calling obstack_free (obstack, NULL); which leaves the obstack requiring reinitialization, fill the obstack's fields with a garbage value. in both cases to try fail faster for use-after-free errors. This patch isn't ready as-is: - I couldn't see an equivalent of CHECKING_P for libiberty, so case (B) would do it even in a production build. - this interracts badly with Valgrind; the latter emits messages about "Invalid write of size 8" "16 bytes inside a block of size 65,536 alloc'd" I think that it merely needs some extra uses of the valgrind annotation macros to fix. - the garbage/poison values I picked were rather arbitrary That said, it's survived bootstrap®rtesting on x86_64-pc-linux-gnu (in conjunction with the previous patch). Thoughts? gcc/ChangeLog: * memory-block.h (memory_block_pool::release): If CHECKING_P, fill the released block with a poison value. libiberty/ChangeLog: * obstack.c (_obstack_free): If OBJ is zero, poison the obstack to highlight the need for reinitialization. --- gcc/memory-block.h | 3 +++ libiberty/obstack.c | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/gcc/memory-block.h b/gcc/memory-block.h index d7b96a3..52c17f9 100644 --- a/gcc/memory-block.h +++ b/gcc/memory-block.h @@ -66,6 +66,9 @@ inline void memory_block_pool::release (void *uncast_block) { block_list *block = new (uncast_block) block_list; +#if CHECKING_P + memset (block, 0xde, block_size); +#endif block->m_next = instance.m_blocks; instance.m_blocks = block; } diff --git a/libiberty/obstack.c b/libiberty/obstack.c index 6d8d672..8df5517 100644 --- a/libiberty/obstack.c +++ b/libiberty/obstack.c @@ -292,6 +292,11 @@ _obstack_free (struct obstack *h, void *obj) else if (obj != 0) /* obj is not in any of the chunks! */ abort (); + + /* If OBJ is zero, the obstack will require reinitialization; poison it. + TODO: make this conditional on being a debug build. */ + if (obj == 0) + memset (h, 0xdd, sizeof (struct obstack)); } _OBSTACK_SIZE_T -- 1.8.5.3