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 |