[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