Skip to content

Commit

Permalink
Always set [[ScriptOrModule]] to null for event handler functions
Browse files Browse the repository at this point in the history
Closes #4267. Related to previous work in #4181.

Tests: web-platform-tests/wpt#15251
  • Loading branch information
domenic committed Feb 8, 2019
1 parent 34af0c8 commit 1d6eb99
Showing 1 changed file with 35 additions and 12 deletions.
47 changes: 35 additions & 12 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -88539,17 +88539,15 @@ document.querySelector("button").addEventListener("click", bound);
</div>

<div class="example">
<p><var>active script</var> can be null if the user clicks on the following button, before any
script ever accesses the button's <code data-x="">onclick</code> property:</p>
<p><var>active script</var> can be null if the user clicks on the following button:</p>

<pre><code class="html" data-x="">&lt;button onclick="Promise.resolve('import(`./example.mjs`)').then(eval)">Click me&lt;/button></code></pre>

<p>In this case, the JavaScript function for the <span data-x="event handlers">event
handler</span> will be created by the <span data-x="getting the current value of the event
handler">get the current value of the event handler</span> algorithm as a direct result of user
action, with no script on the stack (i.e., no <span>active script</span>). Thus, when the
promise machinery calls <span>EnqueueJob</span>, there will be no <span>active script</span> to
pass along.</p>
handler">get the current value of the event handler</span> algorithm, which creates a function
with null [[ScriptOrModule]] value. Thus, when the promise machinery calls
<span>EnqueueJob</span>, there will be no <span>active script</span> to pass along.</p>

<p>As a consequence, this means that when the <code>import()</code> expression is evaluated,
there will still be no <span>active script</span>. Fortunately that is handled by our
Expand Down Expand Up @@ -88801,15 +88799,17 @@ import "https://example.com/foo/../module2.mjs";</code></pre>
</ol>

<div class="example">
<p><var>referencingScriptOrModule</var> is not usually null. One case where it <em>can</em> be
null is if the user clicks the control in the following example:</p>
<p><var>referencingScriptOrModule</var> is not usually null, but will be so for event handlers
per the <span data-x="getting the current value of the event handler">get the current value of
the event handler</span> algorithm. For example, given:</p>

<pre><code class="html" data-x="">&lt;button onclick="import('./foo.mjs')">Click me&lt;/button></code></pre>

<p>In this case, at the time the <code>import()</code> expression runs,
<span>GetActiveScriptOrModule</span> will return null, which will be passed to this abstract
operation when <span data-x="js-HostResolveImportedModule">HostResolveImportedModule</span> is
called by <span>FinishDynamicImport</span>.</p>
<p>If a <code data-x="event-click" class="no-backref">click</code> event occurs, then at the
time the <code>import()</code> expression runs, <span>GetActiveScriptOrModule</span> will
return null, which will be passed to this abstract operation when <span
data-x="js-HostResolveImportedModule">HostResolveImportedModule</span> is called by
<span>FinishDynamicImport</span>.</p>
</div>
</li>

Expand Down Expand Up @@ -90983,6 +90983,29 @@ typedef <span>OnBeforeUnloadEventHandlerNonNull</span>? <dfn>OnBeforeUnloadEvent
<li><p>Remove <var>settings object</var>'s <span>realm execution context</span> from the
<span>JavaScript execution context stack</span>.</p></li>

<li>
<p>Set <var>function</var>.[[ScriptOrModule]] to null.</p>

<div class="note">
<p>This is done because the default behavior, of associating the created function
with the nearest <span data-x="concept-script">script</span> on the stack, can lead to
path-dependent results. For example, an event handler which is first invoked by user
interaction would end up with null [[ScriptOrModule]] (since then this algorithm would be
first invoked when the <span>active script</span> is null), whereas one that is first invoked
by dispatching an event from script would have its [[ScriptOrModule]] set to that script.</p>

<p>Instead, we just always set [[ScriptOrModule]] to null. This is more intuitive anyway; the
idea that the first script which dispatches an event is somehow responsible for the event
handler code is dubious.</p>

<p>In practice, this only affects the resolution of relative URLs via <code>import()</code>,
which consult the <span data-x="concept-script-base-url">base URL</span> of the associated
script. Nulling out [[ScriptOrModule]] means that <span>HostResolveImportedModule</span> and
<span>HostImportModuleDynamically</span> will fall back to the <span>current settings
object</span>'s <span>API base URL</span>.</p>
</div>
</li>

<!-- SCRIPT EXEC, sorta -->
<li><p>Set <var>eventHandler</var>'s <span data-x="event handler value">value</span> to the
result of creating a Web IDL <code>EventHandler</code> callback function object whose object
Expand Down

0 comments on commit 1d6eb99

Please sign in to comment.