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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions