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 11977 - HTML5 spec. seems to unnecessarily ban strict mode event handlers
Summary: HTML5 spec. seems to unnecessarily ban strict mode event handlers
Status: RESOLVED FIXED
Alias: None
Product: HTML WG
Classification: Unclassified
Component: LC1 HTML5 spec (show other bugs)
Version: unspecified
Hardware: All All
: P3 normal
Target Milestone: ---
Assignee: Ian 'Hixie' Hickson
QA Contact: HTML WG Bugzilla archive list
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-02-03 23:14 UTC by Allen Wirfs-Brock
Modified: 2011-08-04 05:05 UTC (History)
7 users (show)

See Also:


Attachments

Description Allen Wirfs-Brock 2011-02-03 23:14:52 UTC
I was browsing Kangax's strict mode test result page (http://kangax.github.com/es5-compat-table/strict-mode/ ) and I noticed that he listed the recognition of a use strict directive of a event handler as a "non-standard" feature that he tests for. This spiked my curiosity as my recollection was the HTML5  event handler content attribute was specified to be text that is an ECMAScript FunctionBody.  FunctionBody may contain a Directive Prologue that includes a use strict directive so, from an ECMAScript perspective, there shouldn't be anything non-standard about a strict mode event handler.

To be sure, I checked the event handler section of the  HTML5 spec (http://dev.w3.org/html5/spec/Overview.html#event-handler-attributes) and to my surprise I discovered that it specifies the creation of the handler function in a manner that, at first glance, seems to explicitly cause the presence of a use strict directive to  be ignored.  Essentially it seems to specify that event handlers specified using the event handler attribute are never executed in ECMAScript 5 strict mode.  I don't know whether or not this was intentional, but it certainly seems wrong.  The "strictness" of an ECMAScript function is an internal and local characteristic of the function.  For a ECMAScript host to say that a use strict directive is ignored is really no different  from saying that IfStatements or any other syntactically valid element of a FunctionBody will be ignored.

The HTML5 spec. get into this trouble because of the way it uses the abstract operation for creating function objects defined by section 13.2 of the ES5 specification (http://www.ecma-international.org/publications/standards/Ecma-262.htm).  In step 2 of the algorithm in HTML5 6.1.6.1 it unconditionally uses False as the Strict parameter to the ES5 13.2 algorithm.  That might seem to exclude the function from strict mode, however that isn't actually  the case. All the Strict parameter to 13.2 controls is whether or not "poison-pill" properties for 'caller' and 'arguments' are created for the function object.  The semantics of strict mode are specified throughout the ES5 specification and are control by the actual lexical occurrence of a use strict directive. The Strict parameter to 13.2 does not alter this semantics.

The HTML5 spec. also contains another related bug.   Step three says "If the previous steps failed to compile the script, then ..." where the "previous steps" pretty clearly references the use of ES5 13.2 in the immediately preceding step 2.  However, there is nothing in ES5 13.2 that concerns the compilation of ECMAScript source text.  Instead 13.2 expects to be passed an valid FunctionBody. That validation ("compilation") must occur somewhere else.

It appears to me that these problem are probably the result of the HTML5 algorithm being patterned after the wrong parts of the ES5 spec.  The appropriate part of the ES5 spec. to use as a model is steps 8-11 of ES5 15.3.2.1.  This is the definition of the Function constructor.   These steps correctly take care of parsing the FunctionBody and handling any resulting syntax errors.  It also calls 13.2 with a correct Strict parameter. Replacing HTML5 6.1.6.1 steps 2-3 with steps modeled after ES5 15.3.2.1 steps, 8, 9, and 11 (step 10 is not applicable) should correct these issues.

Finally, Kangax also lists as a "non-standard" feature the recognition of strict coder as the string argument to setTimeout.  I couldn't find anything the HTML5 spec.  that could be interpreted as excluding strict ECMAScript code in this context.

Here is better language to use in 6.1.6.1:

replace existing steps 2-3 with:
----------------------
2. Let body be the event handler content attribute's new value.
3. If body cannot be parsed as an ECMAScript FunctionBody as specified in [ECMA262] clause 13, then set the corresponding event handler to null and abort these steps.
4.

Using this script execution environment from step 1, create a function object (as defined in ECMAScript edition 5 section 13.2 Creating Function Objects), with:

Parameter list FormalParameterList

    If the attribute is the onerror attribute of the Window object
        Let the function have three arguments, named event, source, and fileno.
    Otherwise
        Let the function have a single argument called event. 

Function body FunctionBody
    The event handler content attribute's new value.
Lexical Environment Scope

        Let Scope be the result of NewObjectEnvironment(the element's Document, the global environment).
        If the element has a form owner, let Scope be the result of NewObjectEnvironment(the element's form owner, Scope).
        Let Scope be the result of NewObjectEnvironment(the element's object, Scope).

    NewObjectEnvironment() is defined in ECMAScript edition 5 section 10.2.2.3 NewObjectEnvironment (O, E). [ECMA262]
Boolean flag Strict
    If body is strict mode code let Strict be true, otherwise let Strict be false.

Let this new function be the only entry in the script's list of code entry-points.
---------------------
Renumber existing steps 4&5 as 5&6
Comment 1 Ian 'Hixie' Hickson 2011-02-03 23:20:13 UTC
Thanks, will look into this.
Comment 2 Ian 'Hixie' Hickson 2011-03-04 00:51:57 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.

Based on my reading the spec, it looks like we actually need to do a little more than was proposed in comment 0, so please do check to make sure I didn't screw anything up.

It would be really nice if the JS spec could just give us hooks that we could use so that we didn't have to worry about updating HTML every time the JS spec revs.
Comment 3 contributor 2011-03-04 00:52:17 UTC
Checked in as WHATWG revision r5933.
Check-in comment: Be better about how we define the creation of scripts for event handler attributes (specifically, how we interact with the JS spec).
http://html5.org/tools/web-apps-tracker?from=5932&to=5933
Comment 4 Allen Wirfs-Brock 2011-03-04 02:06:49 UTC
(In reply to comment #2)
> 
> Based on my reading the spec, it looks like we actually need to do a little
> more than was proposed in comment 0, so please do check to make sure I didn't
> screw anything up.
> 

Step 4 should (its also wrong in ES5 15.3.2.1) be:
<p>If <var title="">body</var> is not parsable as <i>FunctionBody</i> or if parsing detects an early error then abort these steps.</p>

<p class="note"><i>FunctionBody</i> is defined in ECMAScript edition 5 section 13 Function Definition. "Early error" is defined in ECMAScript edition 5 section 16 Errors.<a href="#refsECMA262">[ECMA262]</a></p>


Step 6 is unnecessary, as the specific strict mode restrictions in ES5 section 13.1 relate to the naming of the formal parameters of a function and the fixed set of names you provide in step 7 don't violate any of those restrictions.


> It would be really nice if the JS spec could just give us hooks that we could
> use so that we didn't have to worry about updating HTML every time the JS spec
> revs.

I agree with the goal, but there are some missing ES semantics we still need to address. In this particular case, I think we may be able to describe the desired semantics as a source-to-source transformation of the ES code and avoid having to explicitly reach into the ES5 internal spec. mechanisms.
Comment 5 Ian 'Hixie' Hickson 2011-03-04 07:10:02 UTC
Will fix the issues you raise, thanks.

> > It would be really nice if the JS spec could just give us hooks that we could
> > use so that we didn't have to worry about updating HTML every time the JS spec
> > revs.
> 
> I agree with the goal, but there are some missing ES semantics we still need to
> address. In this particular case, I think we may be able to describe the
> desired semantics as a source-to-source transformation of the ES code and avoid
> having to explicitly reach into the ES5 internal spec. mechanisms.

I really would like to avoid defining a source transformation because that often ends up having far more complicated side-effects than one would expect.

What I mean by a "hook" is just that the ES spec could say "When a specification needs to create a foo using a list of arguments bar and a body baz, it must follow these steps, which return a quux and a gizmo: 1. do something, 2. do something else, 3. do yet more things". Then instead of having to reference specific sections or talk about specific grammar constructs, we can just say "and then create a foo as defined in the ES spec".

There's a number of places where hooks like that would be useful.
Comment 6 Allen Wirfs-Brock 2011-03-05 01:16:08 UTC
(In reply to comment #5)
> 
> I really would like to avoid defining a source transformation because that
> often ends up having far more complicated side-effects than one would expect.
>

I actually think that in some of these cases source transformation is going to be more reliable and durable then hooking into the spec. language.  Basically, the source language and its semantics are managed to ensure a very high degree of backwards compatibility while the internal specification language changes from edition to edition as necessary to define new constructs that are introduced into the language.  The internal spec. language historically has not been design with long term stability as a one of its goals.

Here is a first cut at defining event handlers as such a transformation:
1  Set the corresponding event handler to null.
2  Set up a script execution environment for JavaScript.
3  Let /body/ be the event handler context attribute's new value.
4  If /body/ is can not be parsed as /FunctionBody/ then abort these steps.
5  Let /F/ and /E/ be the text of any two ECMAScript identifiers that do not occur in /body/.
6  If the element has a form owner let /prefix/ be the string "(function (__F__, __E__) {with (__F__) with (__E__) {" otherwise let /prefix/ be the string "(function (__E__) {with (__E__) {" .
7  Replace all occurrences of "__F__" and "__E__" within /prefix/ with the values of /F/ and /E/ respectively
8  If the attribute is the onerror attribute of the Window object let /funcHeader/ be the string "return function (event, source, fileno) {" otherwise let /funcHeader/ be the string "return function (event) {".
9  Let /handlerMaker/ be a string consisting of the in order concatenation of /prefix/, /funcHeader/, /body/, and "}}})".
10 Create an ECMAScript language script from the node on which the attribute is being set using the string value of /handlerMaker/ as the script source.
11 Let /result/ be the value of the initial code entry-point of this script. If an exception was raised, let /result/ be void instead.
12 If /result/ is void, abort these steps.
13 If the element has a form owner call the function that is the the value of /result/ passing the element's form owner , and the element's object as arguments;
14 otherwise call the function that is the the value of /result/ passing  the element's object as the sole argument.
15 Set the corresponding event handler to  the value returned by the function call in step 13 or 14.
    

Note: The script text for a /handerMaker/ for an element with a formowner and which is not a onerror attribute of a Window object:

// If "__F__" or "__S__" occur in <<body>> they are replaced with identifiers that do no occur.
(function (__F__, __S__) {
   with (__F__) with (__S__) { return
       function (event) {
            <<body>>
       }
   }
})

The result value computed in step 11 is the outer function above.
Step 13/14 calls that function to create a closure of the inner function closed over the optional form owner and the element's object.  That function is the event handler value.
------------------------
I think the above formulation is clearer and is going to be much more durable. I see minimal risk of unintended side effects and it will be easier to analyze for such than re-purposed ES5 specification pseudo-code.
 
> What I mean by a "hook" is just that the ES spec could say "When a
> specification needs to create a foo using a list of arguments bar and a body
> baz, it must follow these steps, which return a quux and a gizmo: 1. do
> something, 2. do something else, 3. do yet more things". Then instead of having
> to reference specific sections or talk about specific grammar constructs, we
> can just say "and then create a foo as defined in the ES spec".
> 
> There's a number of places where hooks like that would be useful.

The idea of stable interface points between specifications is an interesting one. Where possible, I still think an "as if" transformation to the source language is preferable but for situations where that isn't expressive enough then a stable inter-specification interface my be a good way to make durable connections between specs. 
However, we should probably continue this discussion somewhere other than in this bug.
Comment 7 Ms2ger 2011-03-08 19:22:11 UTC
(In reply to comment #6)
> The idea of stable interface points between specifications is an interesting
> one. Where possible, I still think an "as if" transformation to the source
> language is preferable but for situations where that isn't expressive enough
> then a stable inter-specification interface my be a good way to make durable
> connections between specs. 

IMO, inter-specification interfaces are much better than string concatenation, as they tend to be much easier to check for unintended side-effects. We've been moving toward this way of specifiying, at least in DOM specs.

See, for example, the definition of the FormData constructor [1], which defers to the "constructing the form data set" algorithm in HTML, which should be the most stable approach.

[1] http://dev.w3.org/2006/webapi/XMLHttpRequest-2/#dom-formdata-form
Comment 8 Ian 'Hixie' Hickson 2011-05-06 01:01:27 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: Partially Accepted
Change Description: see diff given below
Rationale: see comment 4
Comment 9 contributor 2011-05-06 01:02:16 UTC
Checked in as WHATWG revision r6099.
Check-in comment: Fix event handler attribute interaction with ES
http://html5.org/tools/web-apps-tracker?from=6098&to=6099
Comment 10 Michael[tm] Smith 2011-08-04 05:05:55 UTC
mass-moved component to LC1