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.hsCrash happens if-O1/-O2is specified. With-O0program finish normally - Run with
./coin-node +RTS -c -V0 -i0 -DS -A256k. Both-cand-Aflags are necessary. Either removing-cor increasing-Amakes crash go away so it's clearly related to GC somehow. -
-dcore-lintshows 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