Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign upPrevent crashing when a link tag has two or more in-flight requests (fix for issue #15101) #15145
Conversation
highfive
commented
Jan 22, 2017
|
Thanks for the pull request, and welcome! The Servo team is excited to review your changes, and you should hear from @emilio (or someone else) soon. |
highfive
commented
Jan 22, 2017
|
The way we handle the timing issue in other code like XMLHttpRequest is to store a monotonically-increasing id in the element and the network load context, and compare them in the implementation of PreInvoke. |
|
Alright, should I add that to this PR? Is there also a way to write a WPT that checks for these out-of-order responses? |
|
You could write a test that first loads a resource that has a 3 second response delay, then immediately loads a second one with no delay, then waits for 4 seconds and queries the computed style of an element that would be affected. |
| assert!(self.stylesheet.borrow().is_none()); | ||
| *self.stylesheet.borrow_mut() = Some(s); | ||
| let mut sheet = self.stylesheet.borrow_mut(); | ||
| let must_invalidate = sheet.is_some(); |
This comment has been minimized.
This comment has been minimized.
emilio
Jan 23, 2017
Member
I think we don't need to call invalidate_stylesheets here, since the stylesheet loader will do it right after calling set_stylesheet.
Remove this code and maybe add a note about it?
This comment has been minimized.
This comment has been minimized.
SwagColoredKitteh
Jan 23, 2017
Author
Contributor
It might be better to just leave the assert there as it is and do what @jdm suggested, which would fix the underlying issue instead of clear the symptoms. That assert will continue to be useful to find timing issues such as what caused this issue in the first place.
This comment has been minimized.
This comment has been minimized.
emilio
Jan 23, 2017
Member
Note that we still need to support setting a stylesheet when it is loaded and the href changes, or at least (probably preferably?) add support for unsetting it and invalidate_stylesheets after the href changes.
So yeah, let's keep the assertion there, let's add the load counter, and also let's move this must_invalidate logic to handle_stylesheet_url, and unset the stylesheet there.
367c10d
to
23a5fdc
|
Did what @jdm suggested, out-of-order stylesheet responses for the same element should be handled correctly now. There are also 2 tests which verify that this works correctly. These tests do time out, even though they should not, though. Added exceptions for those timeouts in the inis files. |
|
#15159 was filed for followup investigation into the timeouts. |
| @@ -37,6 +37,15 @@ use stylesheet_loader::{StylesheetLoader, StylesheetContextSource, StylesheetOwn | |||
|
|
|||
| unsafe_no_jsmanaged_fields!(Stylesheet); | |||
|
|
|||
| #[derive(JSTraceable, PartialEq, Clone, Copy, HeapSizeOf)] | |||
| pub struct GenerationId(u32); | |||
This comment has been minimized.
This comment has been minimized.
| fn should_invoke(&self) -> bool { | ||
| // We must first check whether the generations of the context and the element match up, | ||
| // else we risk applying the wrong stylesheet when responses come out-of-order. | ||
| let gen = self.elem.root() |
This comment has been minimized.
This comment has been minimized.
emilio
Jan 23, 2017
Member
We should invoke the callback always, just not set the stylesheet if the generation doesn't match. Otherwise we will lose track of the pending load count, which means we'll never fire the load event.
This comment has been minimized.
This comment has been minimized.
emilio
Jan 23, 2017
Member
Also, elem may be a <style> element where there's an @import, or the load could be for an @import rule in general, in which case the generation id doesn't matter. So we should do the check in process_response_eof, an we should check that StylesheetContextSource is a LinkElement.
Note that the imports can theoretically have the same race if mutated from CSSOM before the load finishes, but we don't expose that right now to the web, so it can't happen, so no need to worry about this in this PR.
This comment has been minimized.
This comment has been minimized.
| @@ -215,13 +227,17 @@ impl<'a> StylesheetLoader<'a> { | |||
| integrity_metadata: String) { | |||
| let url = source.url(); | |||
| let document = document_from_node(self.elem); | |||
| let gen = self.elem.downcast::<HTMLLinkElement>() | |||
This comment has been minimized.
This comment has been minimized.
23a5fdc
to
86f3209
|
Fixed issue #15159 and made sure that style elements with imports do not crash servo by not assuming that some downcasts always succeed, also did a few cleanups. |
|
Looks great! I have one minor request, after that this is good to go :) Thanks for fixing this @SwagColoredKitteh! |
| let link = elem.downcast::<HTMLLinkElement>().unwrap(); | ||
| // We must first check whether the generations of the context and the element match up, | ||
| // else we risk applying the wrong stylesheet when responses come out-of-order. | ||
| let should_continue = match self.request_generation_id { |
This comment has been minimized.
This comment has been minimized.
emilio
Jan 24, 2017
Member
let's give this variable a meaningful name, something like:
let is_applicable_stylesheet_load =
self.request_generation_id.map_or(true, |id| id == link.get_request_generation_id());(or other name if you want, I'm pretty bad at it :))
| // else we risk applying the wrong stylesheet when responses come out-of-order. | ||
| let should_continue = match self.request_generation_id { | ||
| Some(gen) => gen == link.get_request_generation_id(), | ||
| None => true, |
This comment has been minimized.
This comment has been minimized.
emilio
Jan 24, 2017
Member
nit: I don't think we use to indent fat arrows visually. In any case, you may be able to write this in a more compact way with map_or, as I did above.
|
Also, travis seems to be complaining about the manifest order, you need to fix that I think: You can run |
86f3209
to
abebf34
|
@bors-servo r+ Thanks for doing this! :) |
|
|
|
@emilio My pleasure! I had a lot of fun searching around the codebase and figuring out what went wrong. :D |
abebf34
to
068f960
|
@bors-servo: r=emilio |
|
|
Prevent crashing when a link tag has two or more in-flight requests (fix for issue #15101) <!-- Please describe your changes on the following line: --> The `HTMLLinkElement::set_stylesheet` function now checks whether there already is a stylesheet, and if there is, calls `Document::invalidate_stylesheets` after modifying `self.stylesheet`. This PR also includes a minimal WPT that causes the panic. This is fundamentally a timing issue, so while this fix prevents the crash, it does not fix the underlying issue. Making a <link> element send a second request before the first can finish and then getting the two stylesheet responses out-of-order will apply the wrong stylesheet, as demonstrated with https://gist.github.com/SwagColoredKitteh/2c24c7fac635445042eda4a30e10420e. r? @emilio --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix #15101 (github issue number if applicable). <!-- Either: --> - [X] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/15145) <!-- Reviewable:end -->
|
|
SwagColoredKitteh commentedJan 22, 2017
•
edited by larsbergstrom
The
HTMLLinkElement::set_stylesheetfunction now checks whether there already is a stylesheet, and if there is, callsDocument::invalidate_stylesheetsafter modifyingself.stylesheet.This PR also includes a minimal WPT that causes the panic.
This is fundamentally a timing issue, so while this fix prevents the crash, it does not fix the underlying issue. Making a <link> element send a second request before the first can finish and then getting the two stylesheet responses out-of-order will apply the wrong stylesheet, as demonstrated with https://gist.github.com/SwagColoredKitteh/2c24c7fac635445042eda4a30e10420e.
r? @emilio
./mach build -ddoes not report any errors./mach test-tidydoes not report any errorsThis change is