Uninitialized slop words added to single-word closures making debugging harder
Minimum closure size we can have in GHC is currently 2 words (see 1), so for
empty constructors like True
we allocate one empty non-pointer field to make
its size 2.
However those "slop" words are not initialized, and the random values sometimes (always?) correspond to an existing info table or closure address, which makes debugging harder.
For example, in my current build payload[0]
of True
is actually an info
table location:
>>> call printClosure((StgClosure*)&ghczmprim_GHCziTypes_True_closure)
0x6f5a38: ghc-prim:GHC.Types.True(0x553388#)
>>> print ((StgClosure*)&ghczmprim_GHCziTypes_True_closure)->payload[0]
$1 = (struct StgClosure_ *) 0x553388 <ghczmprim_GHCziTypes_MkCoercible_info>
This causes problems when I'm scanning the address space to generate heap graph, or searching for a specific constructor etc.
Implementation-wise the reason for this is because we only update description of the closure (in mkHeapRep), we don't update the actual payload. It's somewhat surprising that this doesn't cause a panic later in code generation (when we see a closure with a non-pointer in its info table but its payload is actually empty) -- apparently this is a case we handle.
I propose we generate 0s for these non-pointer fields to make debugging easier. As far as I know this should not generate any runtime costs as it's not possible to allocate an empty closure in runtime -- all empty constructor closures are statically allocated.
When implemented, this is what I should see when printing True
:
>>> call printClosure((StgClosure*)&ghczmprim_GHCziTypes_True_closure)
0x6f5a38: ghc-prim:GHC.Types.True(0x0#)