Skip to content

Promise.withResolvers(): OOM cleanup use-after-free on current master #1660

Closed

Description

@mschwarzl

Affected code: quickjs.c, js_promise_withResolvers() at current master 954dc53.

A single ordinary JavaScript expression can trigger a native heap use-after-free when a property definition fails under the runtime memory limit:

ASAN_OPTIONS=abort_on_error=1:detect_leaks=0:halt_on_error=1 \
  ./qjs --memory-limit 119434b -e "Promise.withResolvers()"

The exact limit is build-dependent. On the tested Linux x86_64 ASan build, 119434b through 119438b reproduce consistently. ASan reports a READ of size 4 in JS_FreeValueRT, called by js_promise_withResolvers at quickjs.c:56061. The object was freed by JS_DefinePropertyValue at quickjs.c:11538, called from the reject-property definition at quickjs.c:56054.

Expected: Promise.withResolvers() returns or throws OOM cleanly.

Actual: the host process performs a UAF read and aborts under ASan.

Root cause: JS_DefinePropertyValue() consumes and releases val even when it returns an error. js_promise_withResolvers() clears result_promise and resolving_funcs[0] only after successful calls, and never clears resolving_funcs[1]. On failure, exception cleanup releases the stale local again. The promise, resolve, and reject property paths are all statically affected; the command above directly reproduces the reject path.

This was introduced by b0eb4fe (#1173) and is distinct from #1613 / GHSA-crgj-9jv8-xfhq, which fixed stale output from js_create_resolving_functions() before v0.16.0. This reproduces on v0.16.1.

The ownership fix is to set each local to JS_UNDEFINED immediately after the consuming JS_DefinePropertyValue call, before checking its return value. I tested that change in a separate ASan build: no ASan findings across 119400b..119460b or sampled handled-OOM limits, git diff --check passed, and the project suite reported 0/89 errors (9 excluded). A deterministic allocation-failure regression harness does not appear to exist in the current suite.

Reported publicly per SECURITY.md guidance for AI-assisted source findings; the root cause, reproducer, ASan trace, affected history, and fix were independently verified.

Activity

  1. sr5434 commented on Aug 24, 2026

    @sr5434
    Contributor

    How did you find those specific limits? I am trying to integrate it into the test suite but I think running it in the test runner alters what memory limit you need

  2. added a commit that references this issue on Aug 25, 2026
  3. bnoordhuis commented on Aug 25, 2026

    @bnoordhuis
    Contributor

    Fixed, thanks for the report.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions