This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.

Bug 12101 - "Structured clone" can be passed an object with a hostile getter that returns an object identical to itself; "structured clone" does not prevent such an infinite regression.
Summary: "Structured clone" can be passed an object with a hostile getter that returns...
Status: RESOLVED FIXED
Alias: None
Product: HTML WG
Classification: Unclassified
Component: LC1 HTML5 spec (show other bugs)
Version: unspecified
Hardware: Other other
: P3 normal
Target Milestone: ---
Assignee: Ian 'Hixie' Hickson
QA Contact: HTML WG Bugzilla archive list
URL: http://www.whatwg.org/specs/web-apps/...
Whiteboard:
Keywords:
Depends on: 12248
Blocks:
  Show dependency treegraph
 
Reported: 2011-02-17 01:21 UTC by contributor
Modified: 2011-08-12 21:46 UTC (History)
10 users (show)

See Also:


Attachments

Description contributor 2011-02-17 01:21:20 UTC
Specification: http://www.whatwg.org/specs/web-apps/current-work/complete.html
Section: http://www.whatwg.org/specs/web-apps/current-work/#structured-clone

Comment:
"Structured clone" can be passed an object with a hostile getter that returns
an object identical to itself; "structured clone" does not prevent such an
infinite regression.

Posted from: 216.239.45.4 by ian@hixie.ch
Comment 1 Allen Wirfs-Brock 2011-03-07 21:03:09 UTC
I don't understand the issue here. Or perhaps the bug title is just misleading.

How is:

var circular1= { };
circular1.self = circular1;

any different from:

var circular = {get self() {return circular}};

from the perspective of the structured cloning algorithm?

In both cases the top level innovation of the algorithm will capture the reference to the top level object in memory and the recursive call will immediately return that reference.

A more problematic case would seem to be:

function makeAnother() {
   return Object.create(Object.prototype,
        {another:{get: makeAnother, enumerable: true}});}
var infinite = makeAnother();

This produces a lazily constructed infinite chain of objects. Applying the structure clone algorithm should fairly quickly cause  resource exhaustion, either space or time.  This is exactly what happens in current browsers (I tested Safari 5 and FF4, btw FF produces the error much quicker than Safari) if you do:

JSON.stringify(infinite)

From a resource consumption perspective this problem is essentially no different from accessors like:

var loop = {get prop () {while(true);};
var recur = {get prop () {function r() {return r()}; r()}};
var blowheap = {get prop () {var a=[]; while (true) a.push(new Object)}};

Essentially, anytime a Web App API calls back into JavaScript (or any other language) user supplied code there is the possibility that the call back will not terminate or have some other resource consumption failure or the sort that can routinely occur in in script code.  Accessors are such call-backs. Web App specs. are going to have to deal with them either implicitly or explicitly.

The reasonable fix would seem to be to make sure that such call backs only occur at points where such failures can be reasonably dealt with. Either that or explicitly ignore accessors.  This solution may be acceptable for some uses of structured clone but probably isn't reasonable for all arbitrary object property value accesses in all web app APIs.
Comment 2 Ian 'Hixie' Hickson 2011-03-08 04:26:39 UTC
The makeAnother() case is the one to which this bug is referring.

The solution could indeed be as simple as just saying that there is some defined depth to which the algorithm will recurse; it seems unfortunate to hard-code such limits into the platform, though. I guess we could also hard-code a limit that is only increased when getting data from a property with a getter.

In bug 12248 comment 3 Boris mentions some other specific edge cases that come up in this context, such as what happens if such an API is invoked reentrantly or if the event loop is spun during the API call. I think we can probably resolve those problems pretty easily by just making sure that the structured clone algorithm is the very first thing that is run for any API that will eventually invoke it. That way, the problem is reduced to a previously solved problem (showModalDialog).
Comment 3 Simon Pieters 2011-05-26 20:07:26 UTC
Do we need to support getters at all? Also seems a bit annoying if a getter does sync XHR or alert.
Comment 4 Ian 'Hixie' Hickson 2011-06-03 20:20:14 UTC
EDITOR'S RESPONSE: This is an Editor's Response to your comment. If you are satisfied with this response, please change the state of this bug to CLOSED. If you have additional information and would like the editor to reconsider, please reopen this bug. If you would like to escalate the issue to the full HTML Working Group, please add the TrackerRequest keyword to this bug, and suggest title and text for the tracker issue; or you may create a tracker issue yourself, if you are able to do so. For more details, see this document:
   http://dev.w3.org/html5/decision-policy/decision-policy.html

Status: Accepted
Change Description: see diff given below
Rationale: Concurred with reporter's comments.

For now I've used a one-step depth limit. That can be adjusted as desired.
Comment 5 contributor 2011-06-03 20:20:34 UTC
Checked in as WHATWG revision r6185.
Check-in comment: Make structured clone handle getters.
http://html5.org/tools/web-apps-tracker?from=6184&to=6185
Comment 6 Jonas Sicking (Not reading bugmail) 2011-07-05 17:28:00 UTC
Why do we need to do anything here at all? Why is this different from:

while(1) {}

Browsers have to deal with malicious script that never finishes no matter what. That mechanism should catch this case too.
Comment 7 Cameron McCormack 2011-07-05 21:46:37 UTC
I agree with Jonas.  Even simple type conversions can result in this, e.g.

  element.id = { toString: function() { while(1); } };

There are many situations where DOM objects have to call in to JS code, and calling a getter property is just one of them.
Comment 8 Jonas Sicking (Not reading bugmail) 2011-07-07 23:42:24 UTC
Reopening and requesting WONTFIX.

The checked in "fix" for this bug simply adds implementation complexity and usage restrictions without solving any real problems.
Comment 9 Ian 'Hixie' Hickson 2011-07-14 21:52:40 UTC
Fair enough. I'll replace this with a warning to implementors.
Comment 10 Michael[tm] Smith 2011-08-04 05:06:37 UTC
mass-moved component to LC1
Comment 11 Ian 'Hixie' Hickson 2011-08-12 21:45:56 UTC
EDITOR'S RESPONSE: This is an Editor's Response to your comment. If you are satisfied with this response, please change the state of this bug to CLOSED. If you have additional information and would like the editor to reconsider, please reopen this bug. If you would like to escalate the issue to the full HTML Working Group, please add the TrackerRequest keyword to this bug, and suggest title and text for the tracker issue; or you may create a tracker issue yourself, if you are able to do so. For more details, see this document:
   http://dev.w3.org/html5/decision-policy/decision-policy.html

Status: Accepted
Change Description: see diff given below
Rationale: Concurred with comment 6.
Comment 12 contributor 2011-08-12 21:46:13 UTC
Checked in as WHATWG revision r6434.
Check-in comment: Don't bother protecting structured cloning from a getter with infinite regression, since we can't protect it from a non-terminating getter anyway. Reverts part of r6185.
http://html5.org/tools/web-apps-tracker?from=6433&to=6434