Summary
A method that exists on Uint8Array (and its prototype) reads as undefined under typeof when accessed as a property value, even though it dispatches correctly when called:
typeof Uint8Array.prototype.toBase64 // node: "function" perry: "undefined"
typeof Uint8Array.fromBase64 // node: "function" perry: "undefined"
const b = new Uint8Array([0,1,2]);
b.toBase64({ alphabet: "base64url", omitPadding: true }); // works on perry
Uint8Array.fromBase64("AAEC", { alphabet: "base64url" }); // works on perry
So the property-read form (X.prototype.m / X.staticM) returns undefined while the call form (obj.m(...)) dispatches to the real implementation. Feature-detection code that gates on typeof X.prototype.m === "function" (or truthiness of X.staticM) therefore picks its fallback path on Perry even though the native method is present.
Impact
This is the reason jose/Auth.js took its atob/btoa base64 fallback instead of the native Uint8Array.toBase64/fromBase64 path (surfaced while fixing #6673): jose does Uint8Array.prototype.toBase64 ? native : fallback and Uint8Array.fromBase64 ? native : fallback, both of which read falsy on Perry. The fallback then hit the separate atob bug (#6673). Fixing this typeof-visibility gap would also route such libraries onto their native fast path.
Likely related to how the modern Uint8Array base64/hex methods (toBase64/fromBase64/toHex/fromHex/setFromBase64) are registered — dispatchable but not materialized as readable prototype/static property values (typeof, in, hasOwnProperty, destructuring, Object.getOwnPropertyNames would all likely disagree with Node).
Repro: the snippet above; observed on main @ ad91f35, macOS arm64. /tmp/gsct/bcrepro/b64.cjs in the finding session.
Summary
A method that exists on
Uint8Array(and its prototype) reads asundefinedundertypeofwhen accessed as a property value, even though it dispatches correctly when called:So the property-read form (
X.prototype.m/X.staticM) returnsundefinedwhile the call form (obj.m(...)) dispatches to the real implementation. Feature-detection code that gates ontypeof X.prototype.m === "function"(or truthiness ofX.staticM) therefore picks its fallback path on Perry even though the native method is present.Impact
This is the reason jose/Auth.js took its
atob/btoabase64 fallback instead of the nativeUint8Array.toBase64/fromBase64path (surfaced while fixing #6673): jose doesUint8Array.prototype.toBase64 ? native : fallbackandUint8Array.fromBase64 ? native : fallback, both of which read falsy on Perry. The fallback then hit the separateatobbug (#6673). Fixing this typeof-visibility gap would also route such libraries onto their native fast path.Likely related to how the modern
Uint8Arraybase64/hex methods (toBase64/fromBase64/toHex/fromHex/setFromBase64) are registered — dispatchable but not materialized as readable prototype/static property values (typeof,in,hasOwnProperty, destructuring,Object.getOwnPropertyNameswould all likely disagree with Node).Repro: the snippet above; observed on main @ ad91f35, macOS arm64.
/tmp/gsct/bcrepro/b64.cjsin the finding session.