haikuwebkit/LayoutTests/fast/forms/form-data-associated-elemen...

41 lines
1.2 KiB
HTML
Raw Permalink Normal View History

Harden against layout passes triggered when iterating through HTMLFormElement::associatedElements https://bugs.webkit.org/show_bug.cgi?id=182037 <rdar://problem/36747812> Reviewed by Ryosuke Niwa. Source/WebCore: Observe that HTMLFormElement::associatedElements returns a const reference to a Vector of raw FormAssociatedElement pointers. In various call sites that iterate through these associated elements using this function, some require synchronous layout updates per iteration, which can lead to a bad time when combined with the first observation. To address this, we introduce HTMLFormElement::copyAssociatedElementsVector. This returns a new vector containing strong Refs to each associated element. From each call site that may trigger synchronous layout and execute arbitrary script while iterating over associated form elements, we instead use iterate over protected FormAssociatedElements. From each call site that currently doesn't (and shouldn't) require a layout update, we use the old version that returns a list of raw FormAssociatedElement pointers, but add ScriptDisallowedScopes to ensure that we never execute script there in the future. Test: fast/forms/form-data-associated-element-iteration.html * html/DOMFormData.cpp: (WebCore::DOMFormData::DOMFormData): Change to use copyAssociatedElementsVector(). * html/FormController.cpp: (WebCore::recordFormStructure): (WebCore::FormController::restoreControlStateIn): Change to use copyAssociatedElementsVector(). * html/HTMLFieldSetElement.cpp: (WebCore::HTMLFieldSetElement::copyAssociatedElementsVector const): (WebCore:: const): (WebCore::HTMLFieldSetElement::length const): Refactor to use unsafeAssociatedElements(). * html/HTMLFieldSetElement.h: * html/HTMLFormControlsCollection.cpp: (WebCore:: const): (WebCore::HTMLFormControlsCollection::copyFormControlElementsVector const): (WebCore::HTMLFormControlsCollection::customElementAfter const): (WebCore::HTMLFormControlsCollection::updateNamedElementCache const): Refactor these to use unsafeAssociatedElements(). * html/HTMLFormControlsCollection.h: * html/HTMLFormElement.cpp: (WebCore::HTMLFormElement::unsafeAssociatedElements const): (WebCore::HTMLFormElement::copyAssociatedElementsVector const): * html/HTMLFormElement.h: * loader/FormSubmission.cpp: (WebCore::FormSubmission::create): Refactor to use copyAssociatedElementsVector(). Source/WebKitLegacy/mac: Rename associatedElements() to unsafeAssociatedElements(), and add ScriptDisallowedScopes. See WebCore ChangeLog for more details. * WebView/WebHTMLRepresentation.mm: (-[WebHTMLRepresentation elementWithName:inForm:]): (-[WebHTMLRepresentation controlsInForm:]): LayoutTests: Add a new layout test covering these hardening changes. See WebCore ChangeLog for more details. * fast/forms/form-data-associated-element-iteration-expected.txt: Added. * fast/forms/form-data-associated-element-iteration.html: Added. Canonical link: https://commits.webkit.org/197864@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@227479 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-01-24 08:19:16 +00:00
<!DOCTYPE html>
<html>
<form id="form"></form>
<div>This test passes if the web content process does not crash.</div>
<script>
if (window.testRunner)
testRunner.dumpAsText();
textAreaCount = 100;
for (let i = 1; i <= textAreaCount; ++i) {
let textarea = document.createElement("textarea");
textarea.id = textarea.name = `textarea-${i}`;
form.appendChild(textarea);
}
layoutCount = 1;
frame = document.body.appendChild(document.createElement("iframe"));
frame.contentWindow.matchMedia("(max-width: 100px)").addListener(listener);
new FormData(form);
function listener() {
if (layoutCount == textAreaCount - 1) {
for (let i = 0; i <= textAreaCount; ++i) {
let textarea = document.getElementById(`textarea-${i}`);
if (!textarea)
continue;
textarea.remove();
textarea = null;
}
}
if (layoutCount <= textAreaCount) {
frame.contentWindow.matchMedia(`(max-width: ${layoutCount + 1}px)`).addListener(listener);
frame.width = layoutCount++;
}
}
form.remove();
</script>
</html>