Module loading: stale resolution state after failure and pending imports when Promise constructor/species is overridden

Aperta
#599 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 3 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, compilers

Direzione di ricerca

Start in js_resolve_module() in quickjs.c and JS_LoadModuleInternal() near the cited locations. Trace how resolution state changes when dependency loading fails, then inspect perform_promise_then() and its failure handling for internal module reactions. Reproduce both cases from the issue and verify retries leave a consistent module graph and dynamic imports settle after the job queue drains.

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

Descrizione

Tested against bellard/quickjs commit 712e8c0ca26949477c38f91dbaf955cc48e2f261 (2026-11-02). Both problems reproduce with the unmodified upstream code.

1. Failed dependency resolution leaves a module marked as resolved

Steps to reproduce:

  1. Install a synchronous module loader that can temporarily fail to load dep.js.
  2. Compile this module with JS_EVAL_FLAG_COMPILE_ONLY while the dependency is available:
    import { value } from "./dep.js";
    globalThis.answer = value;
    
  3. Serialize it using JS_WriteObject(..., JS_WRITE_OBJ_BYTECODE), then deserialize it into a new context using JS_ReadObject(..., JS_READ_OBJ_BYTECODE).
  4. Make the loader reject dep.js, then call JS_ResolveModule() on the deserialized module.
  5. Restore the dependency and call JS_ResolveModule() again.
  6. Execute the module with JS_EvalFunction().

Actual behavior: The first resolution returns -1. The second returns 0 without loading the dependency, and evaluation crashes with SIGSEGV.

Expected behavior: Failed resolution should leave a consistent module graph. A subsequent resolution should either retry successfully or report an error; it should not report success with unresolved dependency pointers.

In js_resolve_module(), m->resolved is set before traversing dependencies and is not rolled back on failure. Subsequent calls therefore skip the incomplete graph.

2. Dynamic import can remain pending after Promise constructor/species customization

With a valid dep.js containing:

export const value = 42;

Evaluate:

Object.defineProperty(Promise.prototype, "constructor", {
  configurable: true,
  get() {
    return 123;
  }
});

globalThis.result = import("./dep.js");

Drain the job queue and inspect result using JS_PromiseState().

Actual behavior: The getter is invoked, and the import promise remains pending after the job queue is empty. The same behavior occurs when overriding Promise[Symbol.species] instead, or when the getter throws. JS_LoadModule() is also affected.

Expected behavior: Registering internal module evaluation reactions should not invoke user-defined Promise constructor/species getters. The import should fulfill with the module namespace.

JS_LoadModuleInternal() calls js_promise_then(), which performs a species lookup. If that lookup fails, the returned exception is discarded and the outer promise is never settled. Using the internal perform_promise_then() mechanism, with appropriate failure handling, should avoid this lookup.

Lingua principale
C
Stelle
11.1k
Fork
1.2k
Merge medio
11h 20m
PR unite (30g)
1

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 bellard/quickjs

Tutte le issue di bellard/quickjs

Issue simili

Altre issue su C

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.