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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions