Many array-like native objects do not follow ecma262 specification on Reflect.set
Reported by
i73hi64d...@gmail.com,
Jun 1 2018
|
|||||||||
Issue description
UserAgent: A Fake User Agent
Steps to reproduce the problem:
1. Make `a` be a variable referencing `window` or `navigator.plugins`;
2. Execute `'use strict'; a[0] = {};`
3. Execute `Reflect.set(a, '0', {}, a)`
What is the expected behavior?
If the Step 2 throws, Step 3 should return `false`.
This can be deduced from the ECMA262 Specification as follows:
1. When an assignment operation `a[0] = {}` is evaluated, it performs `PutValue` operation [1]
2. The `PutValue` operation calls `a.[[Set]]('0', {}, a)` [2]
3. On the other hand, when `Reflect.set(a, '0', {}, a)` is evaluated, it performs `a.[[Set]]('0', {}, a)` [3]
4. Since both performs an identical operation, result of it should be identical.
5. Since `a[0] = {}` throws, and the only case that an assignment operation may throw a `TypeError` is when the `[[Set]]` operation returns `false`, it must have returned `false`.
6. However, since `Reflect.set` returns `true`, it means the `[[Set]]` operation must have returned `true`, a contradiction.
[1] https://tc39.github.io/ecma262/#sec-assignment-operators-runtime-semantics-evaluation
[2] https://tc39.github.io/ecma262/#sec-putvalue
[3] https://tc39.github.io/ecma262/#sec-reflect.set
What went wrong?
Step 2 throws, but Step 3 returns `true`.
Did this work before? N/A
Chrome version: 68.0.3440.7 Channel: dev
OS Version: 10.0
Flash Version:
On Firefox 62, Step 2 throws and Step 3 returns `false`, so this issue is not affected.
On Edge 41, Step 2 does not throw (assignment succeeds) and Step 3 returns `true`, so this issue is not affected.
,
Jun 1 2018
,
Jun 1 2018
It appears to me that we're respecting ShouldThrowOnError from V8, which says: * \note Always `false` when intercepting `Reflect.set()` * independent of the language mode. which is why we're not throwing. +some V8 folk to comment on whether this is the right thing
,
Jun 1 2018
- navigator.mimeTypes manifests the same issue. Any other object that throws a `TypeError` with message `Failed to set an indexed property on '....': Index property setter is not supported.` may be affected by this issue.
- Such objects seem to not be complying to spec with respect to `Reflect.defineProperty` as well.
`Object.defineProperty(window, '0', { value: {}, configurable: true})` throws, but
`Reflect.defineProperty(window, '0', { value: {}, configurable: true})` returns `true.
,
Jun 3 2018
,
Jun 5 2018
From reading the spec, I agree with the OP. We should return false for the `Reflect.set` case. Similar to how module namespace objects work: https://cs.chromium.org/chromium/src/v8/src/accessors.cc?l=258-265&rcl=20425a75e22b7a9b632bb1073393a2bee3cba7b8 I suspect this requires a fix in the bindings code and not V8.
,
Jun 5 2018
,
Jun 5 2018
The issue seems to be related to ECMA262 Specification which is out of TE-scope. Hence, adding label TE-NeedsTriageHelp for further investigation from dev team. Thanks...!!
,
Jun 5 2018
#6: Which should return false; Reflect.set or ShouldThrowOnError? The bindings is respecting V8's ShouldThrowOnError, just as ModuleNamespaceEntrySetter is.
,
Jun 5 2018
#9: The PropertyCallbackInfo::GetReturnValue of the accessor should be set to false. Is this already the case?
,
Jun 6 2018
Re #10: Is it the V8 API specification?
v8/include/v8.h says:
/**
* See `v8::GenericNamedPropertySetterCallback`.
*/
typedef void (*IndexedPropertySetterCallback)(
uint32_t index,
Local<Value> value,
const PropertyCallbackInfo<Value>& info);
and GenericNamedPropertySetterCallback says:
/**
* Interceptor for set requests on an object.
*
* Use `info.GetReturnValue()` to indicate whether the request was intercepted
* or not. If the setter successfully intercepts the request, i.e., if the
* request should not be further executed, call
* `info.GetReturnValue().Set(value)`. If the setter
* did not intercept the request, i.e., if the request should be handled as
* if no interceptor is present, do not not call `Set()`.
*
* \param property The name of the property for which the request was
* intercepted.
* \param value The value which the property will have if the request
* is not intercepted.
* \param info Information about the intercepted request, such as
* isolate, receiver, return value, or whether running in `'use strict'` mode.
* See `PropertyCallbackInfo`.
*
* See also
* `ObjectTemplate::SetHandler.`
*/
typedef void (*GenericNamedPropertySetterCallback)(
Local<Name> property, Local<Value> value,
const PropertyCallbackInfo<Value>& info);
By the way, NamedPropertySetterCallback says:
/**
* Returns the value if the setter intercepts the request.
* Otherwise, returns an empty handle.
*/
typedef void (*NamedPropertySetterCallback)(
Local<String> property,
Local<Value> value,
const PropertyCallbackInfo<Value>& info);
As far as I can tell from v8.h, there is no such contract for the embedder to return v8::True or v8::False. My understanding has been "whether non-empty handle or empty handle matters, and nothing else matters (or it's recommended to return the value being set)". If it's necessary to return v8::True or v8::False, then I'm happy to change Blink implementation.
I'd like V8 team to clarify the API specification first. Then, we'll follow it.
,
Jun 11 2018
Yang, WDYT?
,
Jun 12 2018
If a return value is set, V8 ignores it and returns true. if no return value is set, V8 returns false. See https://cs.chromium.org/chromium/src/v8/src/objects.cc?sq=package:chromium&q=objects.cc+file:%5Esrc/v8/+package:%5Echromium$&g=0&l=1835 We could change V8 to respect the return value (and enforce it to be boolean), see the TODO in the code. I've made a similar change before at https://codereview.chromium.org/2397603003. Not sure how much work it would be. The quick fix is to change the setters in question such that they don't set a return value in the error case.
,
Jun 12 2018
,
Aug 8
|
|||||||||
►
Sign in to add a comment |
|||||||||
Comment 1 by dtapu...@chromium.org
, Jun 1 2018