Skip to content
GitLab
Projects Groups Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
  • Sign in / Register
  • GHC GHC
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Locked Files
  • Issues 5,399
    • Issues 5,399
    • List
    • Boards
    • Service Desk
    • Milestones
    • Iterations
  • Merge requests 592
    • Merge requests 592
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
    • Test Cases
  • Deployments
    • Deployments
    • Releases
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Code review
    • Insights
    • Issue
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • Glasgow Haskell CompilerGlasgow Haskell Compiler
  • GHCGHC
  • Issues
  • #15906
Closed
Open
Issue created Nov 16, 2018 by Ömer Sinan Ağacan@osa1Maintainer

Stable name allocation causes heap corruption when GC is triggered in the primop

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.

Trac metadata
Trac field Value
Version 8.7
Type Bug
TypeOfFailure OtherFailure
Priority highest
Resolution Unresolved
Component Runtime System
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system
Architecture
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information
Assignee
Assign to
Time tracking