Part of the #3662 cluster (builtins must throw the spec error on an incompatible this).
The primitive-wrapper prototype methods do not perform the spec this brand
check when invoked reflectively on an incompatible receiver. Instead the call
falls back to Object.prototype and returns "[object Object]" rather than
throwing a TypeError.
Affected (each should throw TypeError on a non-matching receiver):
Number.prototype.valueOf, Number.prototype.toLocaleString
Boolean.prototype.toString, Boolean.prototype.valueOf
Symbol.prototype.toString, Symbol.prototype.valueOf
BigInt.prototype.toString, BigInt.prototype.valueOf
(Number.prototype.toFixed/toString/toExponential/toPrecision already throw via
the computed-key dispatch.)
Repro
Number.prototype.valueOf.call({}); // Perry: "[object Object]" Node: TypeError
Boolean.prototype.toString.call({}); // Perry: "[object Object]" Node: TypeError
Symbol.prototype.toString.call({}); // Perry: "[object Object]" Node: TypeError
BigInt.prototype.valueOf.call({}); // Perry: "[object Object]" Node: TypeError
Related wrong-value bug
Even on a valid receiver, the reflective toString returns the wrong value
(the generic Object.prototype.toString is used):
Symbol.prototype.toString.call(Symbol("x")); // Perry: "[object Symbol]" Node: "Symbol(x)"
BigInt.prototype.toString.call(5n, 2); // Perry: "[object BigInt]" Node: "101"
Suggested fix
Install dedicated brand-checking thunks on Number/Boolean/Symbol/BigInt
.prototype (mirror object/collection_proto_thunks.rs): read IMPLICIT_THIS,
verify it is the matching primitive (or its boxed wrapper), throw TypeError
otherwise, and re-dispatch to the existing per-type logic via
js_native_call_method — which also fixes the wrong-value reflective toString.
Part of the #3662 cluster (builtins must throw the spec error on an incompatible
this).The primitive-wrapper prototype methods do not perform the spec
thisbrandcheck when invoked reflectively on an incompatible receiver. Instead the call
falls back to
Object.prototypeand returns"[object Object]"rather thanthrowing a
TypeError.Affected (each should throw
TypeErroron a non-matching receiver):Number.prototype.valueOf,Number.prototype.toLocaleStringBoolean.prototype.toString,Boolean.prototype.valueOfSymbol.prototype.toString,Symbol.prototype.valueOfBigInt.prototype.toString,BigInt.prototype.valueOf(
Number.prototype.toFixed/toString/toExponential/toPrecisionalready throw viathe computed-key dispatch.)
Repro
Related wrong-value bug
Even on a valid receiver, the reflective
toStringreturns the wrong value(the generic
Object.prototype.toStringis used):Suggested fix
Install dedicated brand-checking thunks on
Number/Boolean/Symbol/BigInt.prototype(mirrorobject/collection_proto_thunks.rs): readIMPLICIT_THIS,verify it is the matching primitive (or its boxed wrapper), throw
TypeErrorotherwise, and re-dispatch to the existing per-type logic via
js_native_call_method— which also fixes the wrong-value reflectivetoString.