Skip to content

regression(runtime): captured ArrayBuffer/SharedArrayBuffer/DataView throws "Constructor requires 'new'" (breaks cli.js init) — #06e1ab349 #8724

Description

@proggeramlug

Summary

Since 06e1ab349 (merge landing #8652/#8651/#8647/#8646/#8650), constructing ArrayBuffer / SharedArrayBuffer / DataView via a captured value throws TypeError: Constructor requires 'new' — e.g. const D = DataView; new D(buf), Reflect.construct(DataView, [buf]), class X extends DataView {}, const AB = globalThis.ArrayBuffer; new AB(8). Direct new DataView(buf) / new globalThis.DataView(buf) still work.

Minified/bundled code captures globals into locals pervasively, so this breaks module init broadly. The natively-compiled Claude Code cli.js 2.1.112 bundle throws this at startup on essentially every command (--help, doctor, mcp list, -p, …; only --version escapes via its early exit). Node runs the same bundle fine.

Repro

const ab = () => new ArrayBuffer(8);
const D = DataView;               new D(ab());                  // THROWS (node: ok)
                                  Reflect.construct(DataView,[ab()]); // THROWS (node: ok)
class MV extends DataView {}      new MV(ab());                 // THROWS (node: ok)
const AB = (globalThis as any).ArrayBuffer; new AB(8);         // THROWS (node: ok)
new DataView(ab());               // ok
new (globalThis as any).DataView(ab()); // ok

Map/Set/Promise/Uint8Array captured-then-constructed all work — only AB/SAB/DataView regressed.

Root cause

06e1ab349 switched ArrayBuffer/SharedArrayBuffer/DataView's global [[Call]] behavior from global_this_builtin_noop_thunk to the shared construct_only_builtin_call_thunk (global_this/populate.rs:203). But identify_global_builtin_constructor (class_registry/class_meta.rs) — the func_ptr allow-list the dynamic-new path uses to recover a captured builtin's name and route it to construct.rs's real factory — was never updated to accept the new thunk. So a captured AB/SAB/DataView closure is no longer recognized (returns None), never reaches the "ArrayBuffer" | "SharedArrayBuffer" / "DataView" arms in construct.rs:891/900, and falls through to invoke the bare-call thunk → "Constructor requires 'new'". The previous noop thunk was in the allow-list, which is why this worked before 06e1ab349. Same bug class the WeakMap/RegExp comments in that function already document.

Fix

Add construct_only_builtin_call_thunk to the identify_global_builtin_constructor allow-list — the name-dispatch construct arms already exist. PR incoming.

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