[GHC] #8834: 64-bit windows cabal.exe segfaults in GC
GHC
ghc-devs at haskell.org
Mon Mar 10 10:20:55 UTC 2014
#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
More information about the ghc-tickets
mailing list