Ecma262: Typed array instance used as prototype incorrect perform [[Get]]/[[Set]]

Created on 15 May 2019  路  9Comments  路  Source: tc39/ecma262

Using a Typed Array (or most any exotic object) as as a prototype is weird. But their specification
of [[Get]] and [[Set]] does not correctly deal with the case where the _Rceiver_ argument is not the same object as the exotic array. In this case, a [[Put]] can actually mutate the prototype type object. Consider:

let o = new Int8Array(1)
Object.setPrototypeOf(Array.prototype, o);
const a = [];  //a inherits indirectly from o
a[0] = 4;  //according to current spec. this will set o[0] to 4.

The problem is that 9.4.5.5 does not check if _O_ is different from _Receiver_ and calls IntegerIndexElementSet to mutate _O_ rather than _Receiver_ (which would also be wrong, but for other reasons.

The fix is to change step 2 to:

if SameValue(_O_,_Reciever_) and Type(_P_) is String, then

The same change should also be made to 9.4.5.4

spec bug web reality

All 9 comments

With this code:

let o = new Int8Array(1)
Object.setPrototypeOf(Array.prototype, o);
const a = [];  //a inherits indirectly from o
a[0] = 4;  //according to current spec. this will set o[0] to 4.
print(a[0], o[0]);

I get these results from eshost file.js:

#### Chakra
4 0

#### JavaScriptCore
4 0

#### SpiderMonkey
4 0

#### V8
4 0

#### V8 --harmony
4 0

This suggests that engines are already doing the correct thing, so it's just a bug in the spec.

That means reverting #347, so we'd again get what was originally specified in ES6.

Does that imply that engines implemented it after #347 landed but with the prior behavior?

I guess SpiderMonkey follows what the current spec (including #347) has for 9.4.5.4 [[Get]], but SpiderMonkey's implementation for 9.4.5.5 [[Set]] doesn't seem to comply to the current spec.

LookupOwnPropertyInline returns done = true when a TypedArray object is encountered, so we always stop in NativeGetPropertyInline even for out-of-bounds accesses. But for [[Set]], an out-of-bounds access results in adding a new property in NativeSetProperty and also in SetExistingProperty for in-bounds, but wrong receiver.

So basically the primary reason for any differences in SpiderMonkey's implementation, is that we inspect the [[ArrayLength]] internal slot of the TypedArrray object earlier than specified in the spec.

OK, so I guess the real questions here imo are in this order:

  1. what behavior do we want?
  2. are engines willing to change to the desired behavior?
  3. if so, yay, let's merge that! if not, what's the most desirable behavior that engines are willing to implement, and how does that differ from current reality?

I think I tried to implement the spec behavior for [[Set]] and it's not web compatible: https://bugzilla.mozilla.org/show_bug.cgi?id=1502889

aha, and that points to #1339.

Looks like we may need to revert all or part of #347?

I've totally forgotten about the web-compatibility issue encountered in Firefox.

Looks like we may need to revert all or part of #347?

I guess the [[Get]] part is still okay, but [[Set]] will need to be changed.

And then we need to decide if consistency between [[Get]] and [[Set]] () or between [[Get]] and [[HasProperty]] (*) is more important, because we can't get both.

() That means consistent receiver checks.
(
*) Per the example in #347

What about just adding a branch for into 2 (if SameValue(O,Receiver)) so we don't fall to 3, but still don't set the value onto the prototype?

Was this page helpful?
0 / 5 - 0 ratings