Skip to content

Legacy platform object [[Set]] inconsistent with default JavaScript [[Set]] behavior #1536

@isheludko

Description

@isheludko

What is the issue with the Web IDL Standard?

[[Set]] operation for legacy platform objects has a surprising behavior from JavaScript point of view.

TL;DR;: When a legacy platform object (P) with indexed and named properties set as a prototype of some other object (O) then one can't add indexed properties to O that are "shadowed" by non-writable indexed properties in P (same as in JavaScript), however it's allowed to add named properties to O that are "shadowed" by non-writable named properties in P (surprise!).

This issue is about Chrome not following the existing Web IDL spec while we think that there's a bug in the spec that should be fixed. 
It would be nice if the Web IDL spec would be more in line with the JavaScript spec.

Assume the following setup:

  var p = {}; 
  Object.defineProperty(p, "x", {writable:false});
  Object.defineProperty(p, "0", {writable:false});

  var obj = Object.create(p);
  obj.x = 42;   // (1) rejected, as expected
  obj[0] = 42;  // (2) rejected, as expected

According to the JavaScript spec, [[Set]] operation (1,2) should not create a property since there's a non-writable property with the same name in the prototype chain.
However, this is not the case if the prototype is a legacy platform object exposing non-writable properties (such as HTMLCollection or NamedNodeMap, see examples below).

Moreover there's an asymmetry between readonly named and indexed properties in the prototype chain: stores to the former (3,5) succeeds while stores to the latter (4,6) are rejected.

This behavior is defined by the following step of [[Set]] operation for legacy platform objects:

  2. Let ownDesc be ? LegacyPlatformObjectGetOwnProperty(O, P, true)."

Note that LegacyPlatformObjectGetOwnProperty operation is called with ignoreNamedProps set to true which hides the supported property names and makes the [[Set]] behave like there are no non-writable properties while [[GetOwnProperty]] operation for legacy platform objects states that there are non-writable properties.

The fix would be to pass false as ignoreNamedProps and maybe even drop this parameter completely.

Can you fix this please?


Example with HTMLCollection:

  var element = document.createElement("p");
  element.id = "named";
  document.body.appendChild(element);
  var p = document.getElementsByTagName("p");  // HTMLCollection

  var obj = Object.create(p);
  console.log(Object.getOwnPropertyDescriptor(p, "named").writable);  // false
  console.log(Object.getOwnPropertyDescriptor(p, "0").writable);  // false
  obj.named = 42;  // (3) unexpectedly succeeds
  obj[0] = 42;     // (4) rejected, as expected

(taken from this Web platform test which exposed the issue: https://staging.wpt.fyi/results/dom/collections/HTMLCollection-as-prototype.html?label=master&label=experimental&product=chrome&product=firefox&product=safari&aligned)

Example with NamedNodeMap:

  var element = document.createElement("p");
  element.id = "foo";
  var p = element.attributes;

  var obj = Object.create(p);
  console.log(Object.getOwnPropertyDescriptor(p, "id").writable);  // false
  console.log(Object.getOwnPropertyDescriptor(p, "0").writable);  // false
  obj.id = 42;  // (5) unexpectedly succeeds
  obj[0] = 42;  // (6) rejected, as expected

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions