Skip to content

Buffer: an own property does not shadow a prototype method when the call folds to the inline byte intrinsic #6405

Description

@proggeramlug

Summary

An own property on a Buffer shadows the same-named Buffer.prototype method in Node (a Buffer is an ordinary Uint8Array). Perry honors this on every dynamic dispatch path, but not when codegen can statically prove the receiver is a buffer and the method name is known at compile time — those calls fold to the inline byte-load/store intrinsic (try_emit_buffer_read_intrinsic / its write twin), which reads the bytes directly and never consults the property table.

const b = Buffer.alloc(8);
b[0] = 0xab;
b.readUInt8 = function () { return "shadowed"; };

b.readUInt8(0);        // node: "shadowed"   perry: 171   <-- folds to the intrinsic
b["readUInt8"](0);     // node: "shadowed"   perry: 171   <-- literal key also folds

const k = "readUInt8";
b[k](0);               // node: "shadowed"   perry: "shadowed"  (dynamic path, correct)

Why it is narrow

The fold requires lower_buffer_access_proof to succeed, i.e. the receiver's buffer-ness is provable at compile time. In minified/untyped bundles the proof usually fails, so the call goes through js_native_call_methoddispatch_buffer_method, which checks own props first and is correct. That is why mysql2's MockBuffer idiom (replace the write methods of a zero-length Buffer with no-ops to measure a packet) works in practice.

Fixing it

The honest fix costs a guard on Perry's hottest byte-access path, so it wants a deliberate decision:

  • Runtime flag + branch — a process-global "some buffer has own props" bit, checked before the inline load; the slow path routes to js_native_call_method. One predictable branch per buffer read.
  • Whole-program compile-time flag — disable the intrinsic only for programs that assign to a property whose name is a Buffer.prototype method name. Zero runtime cost, but needs a pre-codegen scan across modules.

Own-property support itself (storage, reads, method-VALUE reads, in, dynamic-key calls, byte indices, stale-address clearing) landed separately; this issue covers only the static-fold case.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions