Skip to content

GC: explicit gc() deadlocks after building a wide dynamic-property object (mutex self-deadlock) #4878

@proggeramlug

Description

@proggeramlug

Found while stress-testing write barriers (main @ 09760e6, macOS arm64).

Repro (deterministic)

const src: any = {};
for (let i = 0; i < 3000; i++) {
    src["f" + i] = { v: i };
}
console.log("built");
gc();                       // never returns
console.log("gc done");     // never printed

Compile and run — the process prints built, then parks forever with ~0% CPU. sample shows the main thread blocked in __psynch_mutexwait via _pthread_mutex_firstfit_lock_slow (8 perry frames above it; release binary is stripped so I couldn't symbolicate which mutex).

Notes

  • Needs the wide dynamic object (thousands of props added via obj[key] = v, which spill to the OVERFLOW_FIELDS side table) + an explicit gc() call. Allocation-pressure-triggered GCs alone do not hang the same program.
  • 3000-key object literals + gc() are fine — only dynamically-added props trigger it.
  • OVERFLOW_FIELDS itself is a thread-local RefCell, so the deadlocked mutex is elsewhere (a RwLock/Mutex reached during the explicit-gc path, possibly lock-then-allocate-then-GC re-entry).
  • This blocked a write-barrier stress repro; the stress test in crates/perry/tests/gc_write_barrier_stress.rs deliberately avoids wide dynamic objects because of this hang.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions