Deterministic crash in compiled program
Summary
I have program which crashes reliably with both GHC 8.4 & 8.6: coin-node.hs
Steps to reproduce
- To compile use:
ghc --make -O1 -debug -rtsopts ./exe/coin-node.hs
Crash happens if-O1/-O2
is specified. With-O0
program finish normally - Run with
./coin-node +RTS -c -V0 -i0 -DS -A256k
. Both-c
and-A
flags are necessary. Either removing-c
or increasing-A
makes crash go away so it's clearly related to GC somehow. -
-dcore-lint
shows no errors
Low level code comes from memory
package. Crash itself is deterministic and always happens in the same place. However test case is fragile and depends on forcing values in particular order. For example removing bang from pubK
makes crash go away
Expected behavior
I expect programs compiled by GHC to not crash unless one gets way too playful with bits.
Core dump analysis
Crash happens in comparing two MutableByteArray# wrappers for equality:
0x00000000004041ac <+316>: mov rsi,QWORD PTR [rdx+0x8]
0x00000000004041b0 <+320>: mov rdi,QWORD PTR [rbp+0x10]
=> 0x00000000004041b4 <+324>: cmp rsi,QWORD PTR [rdi+0x8]
rdi's content is 0x0000420000700000
which is not valid address. However:
(rr) x/* ($rdi >> 8)
0x490680 <stg_ARR_WORDS_info>: 0x4657bfb8
(rr) x/g ($rdi >> 8) + 8
0x4200007008: 0x0000000000000001
(rr) x/8b ($rdi >> 8) + 8 +8
0x4200007010: 0x01 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa 0xaa
So it does point to correct byte array except it got shifted by 8 bits somehow. Using rr one could find how that value gets stored onto stack(?):
0x000000000040412c <+188>: mov rcx,QWORD PTR [rax+0x7]
=> 0x0000000000404130 <+192>: mov QWORD PTR [rbp-0x10],rcx
Very suspicious thing is load from rax+7
. Indeed if we load from rax + 8
we'll get correct value. My only hypothesis is that rax
expected to contain tagged pointer but that tag got lost somehow. rax = 0x42000bf708
so all tag bits are clear.
Environment
- GHC version used: 8.4.4, 8.6.4, 8.6.5
- Operating System: Linux
- System Architecture: x64