mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-26 19:55:39 +00:00
Bug 1413794 - Typed array [[Set]] wrongly inspects the receiver when a canonical numeric string is passed as property name. r=anba
--HG-- extra : rebase_source : f28f2528aa258b0ac3eea15bbaf0690bd1a19ace
This commit is contained in:
parent
476f752665
commit
604d57faf2
@ -21,4 +21,3 @@ function test(arr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test([123]);
|
test([123]);
|
||||||
test(new Int32Array([123]));
|
|
||||||
|
33
js/src/tests/non262/TypedArray/set-with-receiver.js
Normal file
33
js/src/tests/non262/TypedArray/set-with-receiver.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
for (var constructor of anyTypedArrayConstructors) {
|
||||||
|
var receiver = new Proxy({}, {
|
||||||
|
getOwnPropertyDescriptor(p) {
|
||||||
|
throw "fail";
|
||||||
|
},
|
||||||
|
|
||||||
|
defineProperty() {
|
||||||
|
throw "fail";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var ta = new constructor(1);
|
||||||
|
assertEq(Reflect.set(ta, 0, 47, receiver), true);
|
||||||
|
assertEq(ta[0], 47);
|
||||||
|
|
||||||
|
// Out-of-bounds
|
||||||
|
assertEq(Reflect.set(ta, 10, 47, receiver), false);
|
||||||
|
assertEq(ta[10], undefined);
|
||||||
|
|
||||||
|
// Detached
|
||||||
|
if (typeof detachArrayBuffer === "function" &&
|
||||||
|
!isSharedConstructor(constructor))
|
||||||
|
{
|
||||||
|
detachArrayBuffer(ta.buffer)
|
||||||
|
|
||||||
|
assertEq(ta[0], undefined);
|
||||||
|
assertEq(Reflect.set(ta, 0, 47, receiver), false);
|
||||||
|
assertEq(ta[0], undefined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof reportCompare === "function")
|
||||||
|
reportCompare(true, true);
|
@ -1919,6 +1919,36 @@ js::NativeDefineDataProperty(JSContext* cx, HandleNativeObject obj, PropertyName
|
|||||||
return NativeDefineDataProperty(cx, obj, id, value, attrs);
|
return NativeDefineDataProperty(cx, obj, id, value, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ES2019 draft rev e7dc63fb5d1c26beada9ffc12dc78aa6548f1fb5
|
||||||
|
// 9.4.5.9 IntegerIndexedElementSet
|
||||||
|
static bool
|
||||||
|
DefineNonexistentTypedArrayElement(JSContext* cx, Handle<TypedArrayObject*> obj, uint64_t index,
|
||||||
|
HandleValue v, ObjectOpResult& result)
|
||||||
|
{
|
||||||
|
// This method is only called for non-existent properties, which
|
||||||
|
// means any absent indexed property must be out of range.
|
||||||
|
MOZ_ASSERT(index >= obj->length());
|
||||||
|
|
||||||
|
// Steps 1-2 are enforced by the caller.
|
||||||
|
|
||||||
|
// Step 3.
|
||||||
|
// We still need to call ToNumber, because of its possible side
|
||||||
|
// effects.
|
||||||
|
double d;
|
||||||
|
if (!ToNumber(cx, v, &d))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Steps 4-5.
|
||||||
|
// ToNumber may have detached the array buffer.
|
||||||
|
if (obj->hasDetachedBuffer())
|
||||||
|
return result.failSoft(JSMSG_TYPED_ARRAY_DETACHED);
|
||||||
|
|
||||||
|
// Steps 6-9.
|
||||||
|
// We (wrongly) ignore out of range defines.
|
||||||
|
return result.failSoft(JSMSG_BAD_INDEX);
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
DefineNonexistentProperty(JSContext* cx, HandleNativeObject obj, HandleId id,
|
DefineNonexistentProperty(JSContext* cx, HandleNativeObject obj, HandleId id,
|
||||||
HandleValue v, ObjectOpResult& result)
|
HandleValue v, ObjectOpResult& result)
|
||||||
@ -1941,30 +1971,8 @@ DefineNonexistentProperty(JSContext* cx, HandleNativeObject obj, HandleId id,
|
|||||||
// 9.4.5.5 step 2. Indexed properties of typed arrays are special.
|
// 9.4.5.5 step 2. Indexed properties of typed arrays are special.
|
||||||
uint64_t index;
|
uint64_t index;
|
||||||
if (IsTypedArrayIndex(id, &index)) {
|
if (IsTypedArrayIndex(id, &index)) {
|
||||||
// ES2019 draft rev e7dc63fb5d1c26beada9ffc12dc78aa6548f1fb5
|
Rooted<TypedArrayObject*> tobj(cx, &obj->as<TypedArrayObject>());
|
||||||
// 9.4.5.9 IntegerIndexedElementSet
|
return DefineNonexistentTypedArrayElement(cx, tobj, index, v, result);
|
||||||
|
|
||||||
// This method is only called for non-existent properties, which
|
|
||||||
// means any absent indexed property must be out of range.
|
|
||||||
MOZ_ASSERT(index >= obj->as<TypedArrayObject>().length());
|
|
||||||
|
|
||||||
// Steps 1-2 are enforced by the caller.
|
|
||||||
|
|
||||||
// Step 3.
|
|
||||||
// We still need to call ToNumber, because of its possible side
|
|
||||||
// effects.
|
|
||||||
double d;
|
|
||||||
if (!ToNumber(cx, v, &d))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Steps 4-5.
|
|
||||||
// ToNumber may have detached the array buffer.
|
|
||||||
if (obj->as<TypedArrayObject>().hasDetachedBuffer())
|
|
||||||
return result.failSoft(JSMSG_TYPED_ARRAY_DETACHED);
|
|
||||||
|
|
||||||
// Steps 6-9.
|
|
||||||
// We (wrongly) ignore out of range defines.
|
|
||||||
return result.failSoft(JSMSG_BAD_INDEX);
|
|
||||||
}
|
}
|
||||||
} else if (obj->is<ArgumentsObject>()) {
|
} else if (obj->is<ArgumentsObject>()) {
|
||||||
// If this method is called with either |length| or |@@iterator|, the
|
// If this method is called with either |length| or |@@iterator|, the
|
||||||
@ -2651,48 +2659,58 @@ SetNonexistentProperty(JSContext* cx, HandleNativeObject obj, HandleId id, Handl
|
|||||||
return DefineNonexistentProperty(cx, obj, id, v, result);
|
return DefineNonexistentProperty(cx, obj, id, v, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsQualified && obj->is<TypedArrayObject>()) {
|
||||||
|
// 9.4.5.5 step 2. Indexed properties of typed arrays are special.
|
||||||
|
uint64_t index;
|
||||||
|
if (IsTypedArrayIndex(id, &index)) {
|
||||||
|
Rooted<TypedArrayObject*> tobj(cx, &obj->as<TypedArrayObject>());
|
||||||
|
return DefineNonexistentTypedArrayElement(cx, tobj, index, v, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return SetPropertyByDefining(cx, id, v, receiver, result);
|
return SetPropertyByDefining(cx, id, v, receiver, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// ES2019 draft rev e7dc63fb5d1c26beada9ffc12dc78aa6548f1fb5
|
||||||
* Set an existing own property obj[index] that's a dense element or typed
|
// 9.4.5.9 IntegerIndexedElementSet
|
||||||
* array element.
|
// Set an existing own property obj[index] that's a typed array element.
|
||||||
*/
|
|
||||||
static bool
|
static bool
|
||||||
SetDenseOrTypedArrayElement(JSContext* cx, HandleNativeObject obj, uint32_t index, HandleValue v,
|
SetTypedArrayElement(JSContext* cx, Handle<TypedArrayObject*> obj, uint32_t index, HandleValue v,
|
||||||
ObjectOpResult& result)
|
ObjectOpResult& result)
|
||||||
{
|
{
|
||||||
if (obj->is<TypedArrayObject>()) {
|
// Steps 1-2 are enforced by the caller.
|
||||||
// ES2019 draft rev e7dc63fb5d1c26beada9ffc12dc78aa6548f1fb5
|
|
||||||
// 9.4.5.9 IntegerIndexedElementSet
|
|
||||||
|
|
||||||
// Steps 1-2 are enforced by the caller.
|
// Step 3.
|
||||||
|
double d;
|
||||||
|
if (!ToNumber(cx, v, &d))
|
||||||
|
return false;
|
||||||
|
|
||||||
// Step 3.
|
// Steps 6-7 don't apply for existing typed array elements.
|
||||||
double d;
|
|
||||||
if (!ToNumber(cx, v, &d))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Steps 6-7 don't apply for existing typed array elements.
|
// Steps 8-16.
|
||||||
|
// Silently do nothing for out-of-bounds sets, for consistency with
|
||||||
// Steps 8-16.
|
// current behavior. (ES6 currently says to throw for this in
|
||||||
// Silently do nothing for out-of-bounds sets, for consistency with
|
// strict mode code, so we may eventually need to change.)
|
||||||
// current behavior. (ES6 currently says to throw for this in
|
uint32_t len = obj->as<TypedArrayObject>().length();
|
||||||
// strict mode code, so we may eventually need to change.)
|
if (index < len) {
|
||||||
uint32_t len = obj->as<TypedArrayObject>().length();
|
TypedArrayObject::setElement(obj->as<TypedArrayObject>(), index, d);
|
||||||
if (index < len) {
|
return result.succeed();
|
||||||
TypedArrayObject::setElement(obj->as<TypedArrayObject>(), index, d);
|
|
||||||
return result.succeed();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Steps 4-5.
|
|
||||||
// A previously existing typed array element can only be out-of-bounds
|
|
||||||
// if the above ToNumber call detached the typed array's buffer.
|
|
||||||
MOZ_ASSERT(obj->as<TypedArrayObject>().hasDetachedBuffer());
|
|
||||||
|
|
||||||
return result.failSoft(JSMSG_TYPED_ARRAY_DETACHED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Steps 4-5.
|
||||||
|
// A previously existing typed array element can only be out-of-bounds
|
||||||
|
// if the above ToNumber call detached the typed array's buffer.
|
||||||
|
MOZ_ASSERT(obj->as<TypedArrayObject>().hasDetachedBuffer());
|
||||||
|
|
||||||
|
return result.failSoft(JSMSG_TYPED_ARRAY_DETACHED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set an existing own property obj[index] that's a dense element.
|
||||||
|
static bool
|
||||||
|
SetDenseElement(JSContext* cx, HandleNativeObject obj, uint32_t index, HandleValue v,
|
||||||
|
ObjectOpResult& result)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(!obj->is<TypedArrayObject>());
|
||||||
MOZ_ASSERT(obj->containsDenseElement(index));
|
MOZ_ASSERT(obj->containsDenseElement(index));
|
||||||
|
|
||||||
if (!obj->maybeCopyElementsForWrite(cx))
|
if (!obj->maybeCopyElementsForWrite(cx))
|
||||||
@ -2716,13 +2734,19 @@ SetExistingProperty(JSContext* cx, HandleId id, HandleValue v, HandleValue recei
|
|||||||
{
|
{
|
||||||
// Step 5 for dense elements.
|
// Step 5 for dense elements.
|
||||||
if (prop.isDenseOrTypedArrayElement()) {
|
if (prop.isDenseOrTypedArrayElement()) {
|
||||||
|
// TypedArray [[Set]] ignores the receiver completely.
|
||||||
|
if (pobj->is<TypedArrayObject>()) {
|
||||||
|
Rooted<TypedArrayObject*> tobj(cx, &pobj->as<TypedArrayObject>());
|
||||||
|
return SetTypedArrayElement(cx, tobj, JSID_TO_INT(id), v, result);
|
||||||
|
}
|
||||||
|
|
||||||
// Step 5.a.
|
// Step 5.a.
|
||||||
if (pobj->denseElementsAreFrozen())
|
if (pobj->denseElementsAreFrozen())
|
||||||
return result.fail(JSMSG_READ_ONLY);
|
return result.fail(JSMSG_READ_ONLY);
|
||||||
|
|
||||||
// Pure optimization for the common case:
|
// Pure optimization for the common case:
|
||||||
if (receiver.isObject() && pobj == &receiver.toObject())
|
if (receiver.isObject() && pobj == &receiver.toObject())
|
||||||
return SetDenseOrTypedArrayElement(cx, pobj, JSID_TO_INT(id), v, result);
|
return SetDenseElement(cx, pobj, JSID_TO_INT(id), v, result);
|
||||||
|
|
||||||
// Steps 5.b-f.
|
// Steps 5.b-f.
|
||||||
return SetPropertyByDefining(cx, id, v, receiver, result);
|
return SetPropertyByDefining(cx, id, v, receiver, result);
|
||||||
|
Loading…
Reference in New Issue
Block a user