[GHC] #15906: Stable name allocation causes heap corruption when GC is triggered in the primop

GHC ghc-devs at haskell.org
Fri Nov 16 11:52:26 UTC 2018


#15906: Stable name allocation causes heap corruption when GC is triggered in the
primop
-------------------------------------+-------------------------------------
           Reporter:  osa1           |             Owner:  (none)
               Type:  bug            |            Status:  new
           Priority:  highest        |         Milestone:  8.6.3
          Component:  Runtime        |           Version:  8.7
  System                             |
           Keywords:                 |  Operating System:  Unknown/Multiple
       Architecture:                 |   Type of failure:  None/Unknown
  Unknown/Multiple                   |
          Test Case:                 |        Blocked By:
           Blocking:                 |   Related Tickets:
Differential Rev(s):                 |         Wiki Page:
-------------------------------------+-------------------------------------
 The error is originally reported in #15241, and is caught by the test
 `memo001`
 when run with `-debug` (which only happens in sanity way currently).

 Here's the problem. mkStableName# is defined like this:

 {{{
 stg_makeStableNamezh ( P_ obj )
 {
     W_ index, sn_obj;

     (index) = ccall lookupStableName(obj "ptr");

     /* Is there already a StableName for this heap object?
      *  stable_name_table is a pointer to an array of snEntry structs.
      */
     if ( snEntry_sn_obj(W_[stable_name_table] + index*SIZEOF_snEntry) ==
 NULL ) {
         ALLOC_PRIM (SIZEOF_StgStableName); <------------ PROBLEM HERE
 ----------
         sn_obj = Hp - SIZEOF_StgStableName + WDS(1);
         SET_HDR(sn_obj, stg_STABLE_NAME_info, CCCS);
         StgStableName_sn(sn_obj) = index;
         snEntry_sn_obj(W_[stable_name_table] + index*SIZEOF_snEntry) =
 sn_obj;
     } else {
         sn_obj = snEntry_sn_obj(W_[stable_name_table] +
 index*SIZEOF_snEntry);
     }

     return (sn_obj);
 }
 }}}

 There's a problem in the annotated line: if we allocate a `snEntry` in the
 stable name table, but run out of heap to actually allocate the
 `StgStableName`
 we call GC with incorrect `snEntry` contents. As a reminder, this is
 `snEntry`:

 {{{
 typedef struct {
     StgPtr  addr;        // Haskell object when entry is in use, next free
                          // entry (NULL when this is the last free entry)
                          // otherwise. May be NULL temporarily during GC
 (when
                          // pointee dies).

     StgPtr  old;         // Old Haskell object, used during GC

     StgClosure *sn_obj;  // The StableName object, or NULL when the entry
 is
                          // free
 } snEntry;
 }}}

 In summary, `sn_obj == NULL` means the entry is free. When we trigger the
 GC
 after allocating the `snEntry` but before allocating the `StgStableName`,
 we end
 up calling the GC with `sn_obj == NULL` even though the `snEntry` is not
 actually free. In particular, the `addr` field should be updated by
 `gcStableNameTable`, but it's currently not because `gcStableNameTable`
 sees
 `sn_obj` as NULL and skips the entry.

 The is caught by memo001 when run with -debug.

 I already have a fix and will submit a patch soon.

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


More information about the ghc-tickets mailing list