Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

Failed module link leaves orphan var_refs and aborts JS_FreeRuntime (gc_obj_list assertion)

Aperta
#1,833 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 2 giorni

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
45/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
c
Ambito
backend

Direzione di ricerca

Start with the module-link failure path and JS_FreeRuntime in quickjs.c, using the provided deep.js and repeat.js reproductions. Trace cleanup of rejected module graphs and the orphan var_ref GC objects, then add or update a regression test that runs these imports with assertions enabled. Done means imports reject normally, runtime teardown leaves the GC list empty, and qjs exits without an assertion.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

Summary

A failed module link can leave orphan var_ref GC objects and make JS_FreeRuntime abort, even when the failure is caught through Promise.allSettled. This reproduces in the pure-C qjs CLI, without Rust, an embedding, or retained host values.

Confirmed with assertions enabled on:

  • quickjs-ng v0.15.1, commit fd0a0210b7be00957751871e7e01b8291268fc29
  • quickjs-ng master at commit 5271a40beffef45e2eaccc8d22969cac9a4b394c

A backport of the module-lifetime change in PR #1751 onto v0.15.1 does not resolve this separate failed-link abort. It was also reconfirmed on both unpatched v0.15.1 and that backport with ASan+UBSan enabled.

Minimal standalone reproduction

Create these files in one directory (no other dependencies):

// dep.js
export const a = 1;
// shared.js
let s = 1;
export function get() { return s; }
export let live = 2;
export const touch = () => { s += live; return s; };
// mid.js
import { get } from './shared.js';
import { b } from './dep.js'; // intentionally missing export
let m = 0;
export const g = () => m + get() + b;
// main3.js
import { g } from './mid.js';
export const h = () => g();

The following two entry modules independently trigger the abort:

// deep.js
const r = await Promise.allSettled([
  import('./shared.js'), import('./main3.js'), import('./mid.js')
]);
print(r.map(x => x.status + ':' + String(x.reason)).join(' | '));
// repeat.js
const r = await Promise.allSettled([import('./main3.js'), import('./main3.js')]);
print(r.map(x => x.status + ':' + String(x.reason)).join(' | '));

Run with assertions enabled:

qjs -m deep.js
qjs -m repeat.js

Exact v0.15.1 output for deep.js (exit status 134):

fulfilled:undefined | rejected:SyntaxError: Could not find export 'b' in module 'dep.js' | rejected:SyntaxError: Could not find export 'b' in module 'dep.js'
qjs: quickjs.c:2348: JS_FreeRuntime: Assertion `list_empty(&rt->gc_obj_list)' failed.

Exact v0.15.1 output for repeat.js (exit status 134):

rejected:SyntaxError: Could not find export 'b' in module 'dep.js' | rejected:SyntaxError: Could not find export 'b' in module 'dep.js'
qjs: quickjs.c:2348: JS_FreeRuntime: Assertion `list_empty(&rt->gc_obj_list)' failed.

On master 5271a40, both reach the same assertion at line 2698:

qjs: quickjs.c:2698: JS_FreeRuntime: Assertion `list_empty(&rt->gc_obj_list)' failed.

For comparison, this single-import entry exits normally:

// single.js
const r = await Promise.allSettled([import('./main3.js')]);
print(r.map(x => x.status + ':' + String(x.reason)).join(' | '));

Observations and expected behavior

The first trigger reaches the failing mid.js both directly and through its importer main3.js. The second dynamically imports the same failing graph twice. A separate small embedding using the same graph and the engine's leak dump reports one and two orphan var_ref objects respectively, rather than retained JS objects/functions/promises. The CLI reproduction above removes the embedding entirely.

Expected: the imports reject, the rejections can be handled, and runtime teardown releases the failed graph without aborting. This report concerns failed linking, not native-module finalization. The assertion prevents LeakSanitizer's normal exit check on these failing cases; no claim of a clean leak check is made for that path.

Lingua principale
C
Stelle
3.9k
Fork
389
Merge medio
4g 1h
PR unite (30g)
24

Preparare l'ambiente

Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di quickjs-ng/quickjs

Tutte le issue di quickjs-ng/quickjs

Issue simili

Altre issue su C

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.