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 24361 - document.write should not perform a microtask checkpoint or provide a stable state
Summary: document.write should not perform a microtask checkpoint or provide a stable ...
Status: VERIFIED FIXED
Alias: None
Product: WHATWG
Classification: Unclassified
Component: HTML (show other bugs)
Version: unspecified
Hardware: Other other
: P3 normal
Target Milestone: Unsorted
Assignee: Ian 'Hixie' Hickson
QA Contact: contributor
URL: http://www.whatwg.org/specs/web-apps/...
Whiteboard:
Keywords:
: 24356 (view as bug list)
Depends on:
Blocks:
 
Reported: 2014-01-22 14:56 UTC by contributor
Modified: 2014-02-22 12:01 UTC (History)
5 users (show)

See Also:


Attachments

Description contributor 2014-01-22 14:56:05 UTC
Specification: http://www.whatwg.org/specs/web-apps/current-work/
Multipage: http://www.whatwg.org/C#scriptEndTag
Complete: http://www.whatwg.org/c#scriptEndTag
Referrer: 

Comment:
document.write should not provide a stable state

Posted from: 113.23.85.48
User agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.68 Safari/537.36 OPR/19.0.1326.26 (Edition Next)
Comment 1 Philip Jägenstedt 2014-01-22 15:03:25 UTC
The spec says to provide a stable state for </script> unconditionally. This seems strange, because then document.write('<script></script'+'>'); would provide a stable state, allow sync sections to run while scripts are still running, which seems completely counter to the idea of stable sections.

My understanding is that when an algorithm awaits a stable state, the step following in its sync section should run no sooner that when all current scripts (not just current nesting level) have finished running and no later than before the next time scripts are run. This isn't how the spec states it, but it was how I implemented it in Presto, so I'm arrogantly assuming that any deviation is a spec bug and not a Presto bug.

Experiment: http://software.hixie.ch/utilities/js/live-dom-viewer/?saved=2772
Comment 2 Simon Pieters 2014-01-22 16:28:03 UTC
*** Bug 24356 has been marked as a duplicate of this bug. ***
Comment 3 Simon Pieters 2014-01-22 16:30:55 UTC
"Perform a microtask checkpoint." unconditionally at </script> might also be problematic (I'm not familiar with microtasks), but maybe that should be in a separate bug?
Comment 4 Ian 'Hixie' Hickson 2014-01-24 23:51:49 UTC
I dunno about microtask checkpoints, but I don't understand why there's a problem providing a stable state here, or indeed anywhere, really, so long as the times where this happens are well-defined. What's the risk you're trying to avoid?
Comment 5 Philip Jägenstedt 2014-01-25 17:12:26 UTC
It seems to me that the point of stable states for <video> is that the order in which scripts add/remove elements and attributes doesn't matter, since they are allowed to finish first. Providing a stable state while a script is running is counter to that, so I assumed it was not intentional.

I'm not very worried about actual bugs being caused by this, TBH. Simon, do you think it's fine to leave the spec as is? It'll require some pretty interesting test cases mixing resource selection and document.write, but I guess being able to trigger a stable state at known points in a script could also help testing?
Comment 6 Simon Pieters 2014-01-25 20:20:10 UTC
Yeah I'm OK with leaving it as is. Being able to provide a stable state in a script would indeed help with writing tests, although document.write('<script><\/script>'); looks like quite the hack...
Comment 7 Philip Jägenstedt 2014-01-26 08:09:03 UTC
OK, let's call the INVALID.
Comment 8 Philip Jägenstedt 2014-02-11 04:02:28 UTC
In https://codereview.chromium.org/130983011/ it was pointed out that if we provide a microtask checkpoint for document.write('<script><\/script>') then we also need to test document.write() and document.close() in that mutation callback. 

It's not required for Web compat to provide a microtask checkpoint here, or at least Blink previously didn't. Since it isn't useful and creates new cases that people need to spend time on thinking about and testing, I would suggest this spec change:

"If the parser's script nesting level is zero { Perform a microtask checkpoint; Provide a stable state }"

Pretty please?
Comment 9 Rafael Weinstein 2014-02-11 19:18:26 UTC
There's no way that running a microtask checkpoint synchronously upon document.write('<script></script>') is right.

A central invariant of microtasks is that they execute on a fresh script stack (with zero script stack frames below them). Running the checkpoint at document.write violates that.
Comment 10 Rafael Weinstein 2014-02-14 18:33:17 UTC
For posterity:

A central invariant of the microtask timing has to do with isolation. Work types such as Mutation Observers are examples of *decoupled concerns*. The isolation invariant of the microtask timing guarentees that when a microtask work item is run, it is run on a fresh script stack.

The reason for this has to do with allowing all types of decoupled work to complete before inviting others to begin.

By way of counter-example, to run microtask work as a result of document.write or document.appendChild, risks allowing work types arising from microtask items running while the script which invoked write/appendChild was mid-way through completion some work, creating risk on both sides:

The invoking script risks having it's run-time assumptions invalidated by decoupled concerns which essentially pre-empt it

The invoked scripts risk acting on a state of the world (in most cases, the DOM), that is inconsistent.
Comment 11 Philip Jägenstedt 2014-02-18 07:00:22 UTC
(I renamed the bug title to reflect what I'm actually asking for now.)
Comment 12 Ian 'Hixie' Hickson 2014-02-19 17:03:39 UTC
Why is a nested invocation of the parser parsing the </script> end tag any different than dispatchEvennt() or any of the other cases where we pop the script settings object stack? There's lots of ways to have a microtask checkpoint when script is running. You just need to cause a reentrant callback to be run, and when the stack is popped, it'll run the checkpoint.
Comment 13 Philip Jägenstedt 2014-02-19 17:48:07 UTC
(In reply to Ian 'Hixie' Hickson from comment #12)
> Why is a nested invocation of the parser parsing the </script> end tag any
> different than dispatchEvennt() or any of the other cases where we pop the
> script settings object stack? There's lots of ways to have a microtask
> checkpoint when script is running. You just need to cause a reentrant
> callback to be run, and when the stack is popped, it'll run the checkpoint.

Doesn't "If the stack of script settings objects is now empty" in "clean up after running a callback" mean that no scripts are running?

In any event, that leaves the case in "spin the event loop"... Rafael, what's the plan for that?
Comment 14 Ian 'Hixie' Hickson 2014-02-19 20:35:44 UTC
Oh, right, I forgot that we put in something to not do them on dispatchEvent(). That still seems silly to me.

I guess we can put in the same restriction on the parser stuff. It seems really weird to me that we care whether it's reentrant or not, though. But I don't think it matters all that much one way or the other, so if y'all think it's more important to do it that way, then ok.
Comment 15 Philip Jägenstedt 2014-02-20 13:02:00 UTC
(In reply to Ian 'Hixie' Hickson from comment #14)
> Oh, right, I forgot that we put in something to not do them on
> dispatchEvent(). That still seems silly to me.
> 
> I guess we can put in the same restriction on the parser stuff. It seems
> really weird to me that we care whether it's reentrant or not, though. But I
> don't think it matters all that much one way or the other, so if y'all think
> it's more important to do it that way, then ok.

Since you didn't originally intend for the synchronous sections or microtasks to have a "no scripts are running" restriction, I can understand why it seems silly. AFAICT the restriction isn't strictly needed (the behavior is deterministic without it), but having it has a few benefits:

 * It's closer to existing implementations: I implemented "await a stable state" with that restriction in Presto (admittedly because I failed to understand the spec) and Rafael implemented microtasks with that restriction in Blink.
 * "No scripts are running" is simple to understand, relatively speaking.
 * document.write('<script><\/script>') and document.head.appendChild(script) will be more similar.
Comment 16 Ian 'Hixie' Hickson 2014-02-20 18:50:20 UTC
>  * document.write('<script><\/script>') and
> document.head.appendChild(script) will be more similar.

Sure, but it also means that creating a document just with document.write() will be less like getting a document from the network, so it cuts both ways.

Anyway, done.
Comment 17 contributor 2014-02-20 19:05:03 UTC
Checked in as WHATWG revision r8479.
Check-in comment: Don't provide a stable state when parsing reentrantly, for more consistency with when we run microtask checkpoints
http://html5.org/tools/web-apps-tracker?from=8478&to=8479
Comment 18 Philip Jägenstedt 2014-02-21 18:12:09 UTC
Did you accidentally edit the wrong part of the spec? You added the restriction to the event loop when no tasks (and thus no scripts) are running, instead of the 'An end tag whose tag name is "script"' step I thought we were talking about.

(It's possible that the model of the spec doesn't match the model in Blink, and that I'm confused because of it.)

In any event, I presume this would change again if stable states are expressed in terms of microtasks...
Comment 19 Ian 'Hixie' Hickson 2014-02-21 18:50:06 UTC
Yikes, yeah, that was the wrong part of the spec! I must have been jumping back and forth comparing them and then was on the wrong one when I made the edit...

Thanks for catching this.
Comment 20 contributor 2014-02-21 18:50:20 UTC
Checked in as WHATWG revision r8498.
Check-in comment: Oops, edited the wrong line. (stable state and </script> parsing)
http://html5.org/tools/web-apps-tracker?from=8497&to=8498
Comment 21 Philip Jägenstedt 2014-02-21 19:02:01 UTC
OK, that's much better :) Now reopening again because I expect that Rafael will want the same treatment for microtask checkpoints. (I changed the title of the bug mid-discussion.)
Comment 22 Ian 'Hixie' Hickson 2014-02-21 23:01:50 UTC
Uh, yeah, not sure why but I had it in my head that we were already checking this for microtasks. I guess we only actually check it in "clean up after running a callback". Ok, done. This was my intend when doing the previous checkin.
Comment 23 contributor 2014-02-21 23:02:10 UTC
Checked in as WHATWG revision r8507.
Check-in comment: Prevent microtasks from running reentrantly via the parser.
http://html5.org/tools/web-apps-tracker?from=8506&to=8507
Comment 24 Philip Jägenstedt 2014-02-22 12:01:15 UTC
Looks good, I'll proceed to write tests for this case!