[GHC] #11487: stg_ap_pp_fast doesn't pass the argument in the arity=1 case

GHC ghc-devs at haskell.org
Mon Jan 25 02:56:07 UTC 2016


#11487: stg_ap_pp_fast doesn't pass the argument in the arity=1 case
-----------------------------------+---------------------------------
        Reporter:  rwbarton        |                Owner:
            Type:  bug             |               Status:  new
        Priority:  high            |            Milestone:  8.0.1
       Component:  Runtime System  |              Version:  8.0.1-rc1
      Resolution:                  |             Keywords:
Operating System:  Linux           |         Architecture:  arm
 Type of failure:  Runtime crash   |            Test Case:
      Blocked By:                  |             Blocking:
 Related Tickets:                  |  Differential Rev(s):
       Wiki Page:                  |
-----------------------------------+---------------------------------
Description changed by rwbarton:

@@ -53,1 +53,2 @@
- `r8` (the physical register for R2) in the body of `stg_ap_pp_fast`.
+ `r8` (the physical register for R2) in the body of `stg_ap_ppp_fast`
+ (which has the same problems as `stg_ap_pp_fast`).

New description:

 The body of `stg_ap_pp_fast` looks like
 {{{
             arity = TO_W_(StgFunInfoExtra_arity(%GET_FUN_INFO(R1)));
             ASSERT(arity > 0);
             if (arity == 1) {
                 Sp_adj(-2);
                 W_[Sp+WDS(1)] = R3;
                 W_[Sp+WDS(0)] = stg_ap_p_info;
                 R1 = R1 + 1;
                 jump_SAVE_CCCS(%GET_ENTRY(UNTAG(R1)));
             }
             if (arity == 2) {
                 Sp_adj(0);
                 R1 = R1 + 2;
                 jump %GET_ENTRY(UNTAG(R1)) [R1,R2,R3];
             } else {
                 Sp_adj(-3);
                 W_[Sp+WDS(2)] = R3;
                 W_[Sp+WDS(1)] = R2;
                 if (arity < 4) {
                   R1 = R1 + arity;
                 }
                 BUILD_PAP(2,2,stg_ap_pp_info,FUN);
             }
 }}}
 where
 {{{
 // Jump to target, saving CCCS and restoring it on return
 #if defined(PROFILING)
 #define jump_SAVE_CCCS(target)                  \
     Sp(-1) = CCCS;                              \
     Sp(-2) = stg_restore_cccs_info;             \
     Sp_adj(-2);                                 \
     jump (target) [R1]
 #else
 #define jump_SAVE_CCCS(target) jump (target) [R1]
 #endif
 }}}

 So in the arity=1 case the jump amounts to
 {{{
                 jump (%GET_ENTRY(UNTAG(R1))) [R1]
 }}}
 R1 is the function to apply, but we don't pass its argument, R2!

 Now, possibly by design, the calling convention of `stg_ap_pp_fast` is
 such that the first argument to apply is in R2, which is the same register
 that the function R1 will expect to find its argument in. So if nothing
 happens to disturb R2 (and possibly this is always the case with the NCG),
 then everything is fine. However, it's definitely not fine for the LLVM
 backend, which quite reasonably passes `undef` for the R2, R3, and R4
 arguments when doing the jump. On arm/Android, LLVM decided to clobber
 `r8` (the physical register for R2) in the body of `stg_ap_ppp_fast`
 (which has the same problems as `stg_ap_pp_fast`).

 This caused a crash for the following program:
 {{{
 main = print (read "3"::Int)
 }}}

 This appears to have been broken by commit
 f9265dd369b9e269349930012c25e670248f2a09 which changed the argument list
 for `jump_SAVE_CCCS` from `[*]` to `[R1]`.

--

--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/11487#comment:1>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list