servo/servo

`window.hashchange` events are unthrottled

Opened this issue · 1 comments

Describe the bug:
It's possible to prevent Servo from shutting down cleanly by defining an infinite loop in javascript based on event listeners.

Example:

<!DOCTYPE html>
<meta charset=utf-8>
<title>Servo HashChange loop</title>
<script>
window.onhashchange = function(e) {
    window.location.hash = Math.random().toString();
    console.log('hashchange', window.location.hash);
};

window.location.hash = ""
</script>

When executing this in Servo, the events are processed until attempting to exit, then there is a period where notify_history_changed errors are logged (with warnings on).

Chromium doesn't appear to log anything when this file is opened.

Firefox presents a throttle warning, via rate limiting:
Screenshot 2024-04-20 at 5 56 20 pm

Servo example:

output.mp4

To Reproduce:
Copy the above code to a html file and execute it with Servo with LOG_LEVEL warn.

Platform:
OSX/Sonoma 13.4.1

WPT Test
As an aside, this technique is used in a WPT test,.

a period where notify_history_changed errors are logged (with warnings on)

This originates at

"notify_history_changed error after top-level browsing context closed."

Which I think happens in response to handling

fn handle_navigated_to_fragment(

Interesting to note: we still have the pipeline, but the browsing context is already gone.

The NavigatedToFragment is sent from:

self.send_to_constellation(ScriptMsg::NavigatedToFragment(

Which is called into from

.load_url(replacement_flag, reload_triggered, load_data);

load_url, after sending the message, queues a task to fire the hashchange event, and from that event load_url will be called again if the hash is changed.


Besides the non-existent rate-limiting, the question is why do we not handle the exit message from the constellation, apparently handling the task messages first?

The constellation exit workflow starts at

fn handle_exit(&mut self) {
, not that this sends the exit pipeline message, but also first shuts down the background hang monitor, which should result in skipping task messages which should break the infinite loop(and I guess it does, but why so late?).