
#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