Skip to content

Immutable ArrayBuffer's are almost here. Are we ready? #66346

Open

Description

@jasnell

Every API that receives an ArrayBuffer needs to be updated to correctly handle immutable ArrayBuffers. It looks like we still have a fair number that do not handle them correctly. We need a comprehensive audit and update.

/cc @panva

Activity

  1. panva commented on Sep 27, 2026

    @panva
    Member

    Some issues to look at and chip down on in #66350. Most likely not exhaustive.

  2. added
    never-staleIssues and PRs exempt from automated stale handling.
    on Sep 27, 2026
  3. added
    help wantedIssues that need assistance from volunteers or PRs that need help to proceed.
    v8 engineIssues and PRs related to the V8 dependency.
    on Sep 28, 2026
  4. RohanMali2003 commented on Oct 8, 2026

    @RohanMali2003

    I can work on adding support/error handling for immutable ArrayBuffers in node:crypto (randomFill, randomFillSync, getRandomValues)

  5. Hakaou commented on Oct 21, 2026

    @Hakaou

    Hi @jasnell, I was a little bit curious regarding the serialization part of this audit.

    I reproduced on 26.4 with --js-immutable-arraybuffer and read main at ce9d650. v8.serialize() / v8.deserialize() and the advanced IPC codec keep a bare immutable ArrayBuffer immutable, but any view over one comes back mutable. structuredClone, MessageChannel and Worker keep it. #66350 already lists this. As far as I can tell the host-object record written by _writeHostObject and node_ipc_serdes.cc carries nothing about the backing store.

    What I have in mind is to keep the documented DefaultSerializer contract where only the referenced range is stored and let V8 carry that range as a buffer for immutable views only.

    uint32  typeIndex | 0x80000000   // high bit means an ArrayBuffer value follows instead of length + raw bytes
    value   view.buffer.sliceToImmutable(byteOffset, byteOffset + byteLength)   // writeValue(). V8 tags it immutable and rebuilds it immutable
    

    The invariants are the exact range, Buffers staying Buffers and the encoding of mutable views remaining byte-for-byte unchanged. I verified them in a userland prototype on 26.4. The ipc_serdes reader can follow with ReadValue(). The writer needs a way to build an immutable copy of a range from C++. V8's public API does not offer it yet. So node:v8 first and IPC as a follow-up.

    On compatibility, Node 25.0.0 accepts today's encoding of an immutable view as a mutable view and rejects the new record. Would this record shape be acceptable for immutable views, including rejection by older readers? Or would you prefer a different compatibility strategy?

    Details and measurements

    In the prototype on 26.4, 15/15 mutable values are byte-identical to v8.serialize(). A 6-byte view of a 36-byte immutable buffer serializes to 16 bytes with none of the surrounding bytes. Today it is 11 bytes and mutable on read. Mixed messages, repeated references and cycles round-trip. Zeroing the transport buffer after reading leaves the immutable view intact.

    I could also test two more cases that come with the change. A mutable view read from an immutable transport buffer comes out mutable instead of aliasing the transport. An unknown type index throws an explicit error instead of a TypeError on undefined.

    With Node 25.0.0 reading messages written by 26.4, a bare immutable ArrayBuffer fails with Unable to deserialize cloned data. A view in the current encoding is read and writable. The new record fails with ReadRawBytes() failed. The closest precedents are the BigInt64Array #43571 and Float16Array #55996 index additions. Those added new types rather than re-encoding a view older readers already accept.

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

    help wantedIssues that need assistance from volunteers or PRs that need help to proceed.never-staleIssues and PRs exempt from automated stale handling.v8 engineIssues and PRs related to the V8 dependency.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions