
#8834: 64-bit windows cabal.exe segfaults in GC ----------------------------------+---------------------------------- Reporter: awson | Owner: Type: bug | Status: patch Priority: highest | Milestone: 7.8.1 Component: Compiler | Version: 7.8.1-rc2 Resolution: | Keywords: Operating System: Windows | Architecture: x86_64 (amd64) Type of failure: Runtime crash | Difficulty: Unknown Test Case: | Blocked By: Blocking: | Related Tickets: ----------------------------------+---------------------------------- Comment (by jstolarek): I see something that looks suspicious. In the correct version we have: {{{ c1zB: _r1xg::P64 = R1; if ((Sp + -16) < SpLim) goto c1zC; else goto c1zD; c1zC: R1 = _r1xg::P64; call (stg_gc_enter_1)(R1) args: 8, res: 0, upd: 8; c1zD: (_c1zx::I64) = call "ccall" arg hints: [PtrHint, PtrHint] result hints: [PtrHint] newCAF(BaseReg, _r1xg::P64); if (_c1zx::I64 == 0) goto c1zz; else goto c1zy; c1zz: call (I64[_r1xg::P64])() args: 8, res: 0, upd: 8; c1zy: I64[Sp - 16] = stg_bh_upd_frame_info; I64[Sp - 8] = _c1zx::I64; R2 = c1zA_str; Sp = Sp - 16; call GHC.CString.unpackCString#_info(R2) args: 24, res: 0, upd: 24; }}} In the incorrect one we have: {{{ c1zy: if ((Sp + -16) < SpLim) goto c1zz; else goto c1zA; c1zz: R1 = R1; call (stg_gc_enter_1)(R1) args: 8, res: 0, upd: 8; c1zA: (_c1zu::I64) = call "ccall" arg hints: [PtrHint, PtrHint] result hints: [PtrHint] newCAF(BaseReg, R1); if (_c1zu::I64 == 0) goto c1zw; else goto c1zv; c1zw: call (I64[R1])() args: 8, res: 0, upd: 8; c1zv: I64[Sp - 16] = stg_bh_upd_frame_info; I64[Sp - 8] = _c1zu::I64; R2 = c1zx_str; Sp = Sp - 16; call GHC.CString.unpackCString#_info(R2) args: 24, res: 0, upd: 24; }}} Notice how correct version saves `R1` to local variable. I'm especially worried about this call: {{{ call (I64[_r1xg::P64])() args: 8, res: 0, upd: 8; CORRECT.CMM call (I64[R1])() args: 8, res: 0, upd: 8; WRONG.CMM }}} '''If''' `R1` gets clobbered be earlier ccall to `newCAF(BaseReg, R1)` then this is probably the reason why things go wrong. In that case the right solution would be to tell GHC that the call to `newCAF` defines register `R1` (see `DefinerOfRegs` instance declaration for `GlobalReg`). Then this case should be caught by first guard in `conflicts`. Also, Note [Sinking and calls] seems very relevant here. As a side note: it is really annoying to see these `R1 = R1` assignments. I recall they are eliminated by the code generator but it is frustrating to see them at the Cmm level. I believe the sinking pass should eliminate these assignments but I didn't have enough time to investigate into this further during my internship. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/8834#comment:13 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler