New issue
Advanced search Search tips

Issue 848885 link

Starred by 2 users

Issue metadata

Status: Assigned
Owner:
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Windows
Pri: 2
Type: Bug



Sign in to add a comment

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.
 
Components: -Blink Blink>JavaScript
Components: Blink>Bindings
Cc: yangguo@chromium.org gsat...@chromium.org
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
 - 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. 
Labels: Needs-Triage-M68
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.
Cc: yukishiino@chromium.org peria@chromium.org
Labels: Triaged-ET TE-NeedsTriageHelp
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...!!
#6: Which should return false; Reflect.set or ShouldThrowOnError?

The bindings is respecting V8's ShouldThrowOnError, just as ModuleNamespaceEntrySetter is.
#9: The PropertyCallbackInfo::GetReturnValue of the accessor should be set to false. Is this already the case?
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.

Owner: yangguo@chromium.org
Status: Assigned (was: Unconfirmed)
Yang, WDYT?

Comment 13 by neis@chromium.org, 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.

Comment 14 by neis@chromium.org, Jun 12 2018

Cc: neis@chromium.org
Cc: cbruni@chromium.org

Sign in to add a comment