Constructor info tables generated by GHCi don't return tagged pointers
If we have in a file:
data X = X String unX (X s) = s
And then load the file in ghci with
> data Y = Y String > unX (Unsafe.Coerce.unsafeCoerce (Y "foo")) "Segmentation fault (core dumped)
Even though we are shooting ourselves in the foot there, the constructors
Y are represented identically internally, so the code is supposed to work. And it does work if we either move
unX into ghci'd code, or
Y into compiled code.
After a legthy debugging session with @rwbarton over IRC, we've identified the culprit of this. As [[Commentary/Rts/HaskellExecution/PointerTagging]] states, "In the continuation of an algebraic case, R1 is assumed tagged". And all compiled constructors tag the pointer when entered, e.g:
Dump of assembler code for function ghczmprim_GHCziTypes_False_static_info: 0x00007fffef8dd018 <+0>: 48 ff c3 inc %rbx 0x00007fffef8dd01b <+3>: ff 65 00 jmpq *0x0(%rbp) Dump of assembler code for function base_GHCziBase_Just_static_info: 0x00007ffff03eb780 <+0>: 48 83 c3 02 add $0x2,%rbx 0x00007ffff03eb784 <+4>: ff 65 00 jmpq *0x0(%rbp) Dump of assembler code for function ghczmprim_GHCziTypes_GT_static_info: 0x00007fffef8dd1f8 <+0>: 48 83 c3 03 add $0x3,%rbx 0x00007fffef8dd1fc <+4>: ff 65 00 jmpq *0x0(%rbp) Dump of assembler code for function base_GHCziRTSziFlags_HeapByClosureType_static_info: 0x00007ffff057e768 <+0>: 48 ff c3 inc %rbx // more than 7 constructors so all tags are '1' 0x00007ffff057e76b <+3>: ff 65 00 jmpq *0x0(%rbp)
Whereas all ghci-bound data constructors share the
stg_interp_constr_entry entry code (with an optional trampoline leading there):
Dump of assembler code from 0x7ffff7ff3080 to 0x7ffff7ff3090: => 0x00007ffff7ff3080: jmpq *0x2(%rip) # 0x7ffff7ff3088 0x00007ffff7ff3088: 0x00007fffef4c9388 Dump of assembler code for function stg_interp_constr_entry: 0x00007fffef4c9388 <+0>: ff 65 00 jmpq *0x0(%rbp)
Relevant code: source:libraries/ghci/GHCi/InfoTable.hsc#L32
So in the end, compiled code relies on the assumption that the pointer is tagged, and ghci constructors produce untagged pointers. Even though it is currently impossible to have compiled code pattern match on a ghci constructor, I think this shouldn't happen.