Diff
Modified: branches/safari-602-branch/LayoutTests/ChangeLog (210001 => 210002)
--- branches/safari-602-branch/LayoutTests/ChangeLog 2016-12-19 23:41:45 UTC (rev 210001)
+++ branches/safari-602-branch/LayoutTests/ChangeLog 2016-12-20 00:01:36 UTC (rev 210002)
@@ -1,3 +1,18 @@
+2016-12-19 Babak Shafiei <bshaf...@apple.com>
+
+ Merge r209990.
+
+ 2016-12-18 Brent Fulgham <bfulg...@apple.com>
+
+ Side effects while restting form elements
+ https://bugs.webkit.org/show_bug.cgi?id=165959
+ <rdar://problem/29705967>
+
+ Reviewed by Anders Carlsson.
+
+ * fast/html/form-mutate-expected.txt: Added.
+ * fast/html/form-mutate.html: Added.
+
2016-12-16 Jason Marcell <jmarc...@apple.com>
Merge r209926. rdar://problem/29706846
Copied: branches/safari-602-branch/LayoutTests/fast/html/form-mutate-expected.txt (from rev 209990, trunk/LayoutTests/fast/html/form-mutate-expected.txt) (0 => 210002)
--- branches/safari-602-branch/LayoutTests/fast/html/form-mutate-expected.txt (rev 0)
+++ branches/safari-602-branch/LayoutTests/fast/html/form-mutate-expected.txt 2016-12-20 00:01:36 UTC (rev 210002)
@@ -0,0 +1,5 @@
+PASS Passes if we do not crash.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Copied: branches/safari-602-branch/LayoutTests/fast/html/form-mutate.html (from rev 209990, trunk/LayoutTests/fast/html/form-mutate.html) (0 => 210002)
--- branches/safari-602-branch/LayoutTests/fast/html/form-mutate.html (rev 0)
+++ branches/safari-602-branch/LayoutTests/fast/html/form-mutate.html 2016-12-20 00:01:36 UTC (rev 210002)
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script>
+window.jsTestIsAsync = true;
+
+function runTest() {
+ output.value = "test value";
+ output.appendChild(inserted_div);
+
+ document.getElementById("output").addEventListener('DOMSubtreeModified', function() {
+ for(var i=0; i<20; i++) {
+ form.appendChild(document.createElement("input"));
+ }
+ }, false);
+
+ form.reset();
+ setTimeout(function() {
+ testPassed("Passes if we do not crash.");
+ finishJSTest();
+ }, 0);
+}
+</script>
+</head>
+<body _onload_="runTest()">
+ <div id="inserted_div">foo</div>
+ <form id="form" _onchange_="eventhandler()">
+ <input type="text" value="foo">
+ <output id="output" _oninput_="eventhandler()"></output>
+ <input type="text" value="foo">
+ </form>
+</body>
+</html>
Modified: branches/safari-602-branch/Source/WebCore/ChangeLog (210001 => 210002)
--- branches/safari-602-branch/Source/WebCore/ChangeLog 2016-12-19 23:41:45 UTC (rev 210001)
+++ branches/safari-602-branch/Source/WebCore/ChangeLog 2016-12-20 00:01:36 UTC (rev 210002)
@@ -1,3 +1,30 @@
+2016-12-19 Babak Shafiei <bshaf...@apple.com>
+
+ Merge r209990.
+
+ 2016-12-18 Brent Fulgham <bfulg...@apple.com>
+
+ Side effects while restting form elements
+ https://bugs.webkit.org/show_bug.cgi?id=165959
+ <rdar://problem/29705967>
+
+ Reviewed by Anders Carlsson.
+
+ _javascript_ logic can run while resetting FormElement objects. This can
+ lead to unintended side-effets and other unwanted behavior. We should
+ protect these elements during the reset.
+
+ Test: fast/html/form-mutate.html
+
+ * html/HTMLFormElement.cpp:
+ (WebCore::HTMLFormElement::HTMLFormElement): Switch to C++11 initialization.
+ (WebCore::HTMLFormElement::reset): Protect elements until the reset
+ operation is finished.
+ (WebCore::HTMLFormElement::resetAssociatedFormControlElements): Added to share
+ code with 'resumeFromDocument'.
+ (WebCore::HTMLFormElement::resumeFromDocument): Protect elements until the
+ reset operation is finished.
+
2016-12-16 Jason Marcell <jmarc...@apple.com>
Merge r209926. rdar://problem/29706846
Modified: branches/safari-602-branch/Source/WebCore/html/HTMLFormElement.cpp (210001 => 210002)
--- branches/safari-602-branch/Source/WebCore/html/HTMLFormElement.cpp 2016-12-19 23:41:45 UTC (rev 210001)
+++ branches/safari-602-branch/Source/WebCore/html/HTMLFormElement.cpp 2016-12-20 00:01:36 UTC (rev 210002)
@@ -2,7 +2,7 @@
* Copyright (C) 1999 Lars Knoll (kn...@kde.org)
* (C) 1999 Antti Koivisto (koivi...@kde.org)
* (C) 2001 Dirk Mueller (muel...@kde.org)
- * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2004-2010, 2012-2016 Apple Inc. All rights reserved.
* (C) 2006 Alexey Proskuryakov (a...@nypop.com)
*
* This library is free software; you can redistribute it and/or
@@ -51,6 +51,7 @@
#include "Settings.h"
#include <limits>
#include <wtf/Ref.h>
+#include <wtf/SetForScope.h>
namespace WebCore {
@@ -58,13 +59,6 @@
HTMLFormElement::HTMLFormElement(const QualifiedName& tagName, Document& document)
: HTMLElement(tagName, document)
- , m_associatedElementsBeforeIndex(0)
- , m_associatedElementsAfterIndex(0)
- , m_wasUserSubmitted(false)
- , m_isSubmittingOrPreparingForSubmission(false)
- , m_shouldSubmit(false)
- , m_isInResetFunction(false)
- , m_wasDemoted(false)
#if ENABLE(REQUEST_AUTOCOMPLETE)
, m_requestAutocompletetimer(*this, &HTMLFormElement::requestAutocompleteTimerFired)
#endif
@@ -375,19 +369,30 @@
if (m_isInResetFunction || !frame)
return;
- m_isInResetFunction = true;
+ Ref<HTMLFormElement> protectedThis(*this);
- if (!dispatchEvent(Event::create(eventNames().resetEvent, true, true))) {
- m_isInResetFunction = false;
+ SetForScope<bool> isInResetFunctionRestorer(m_isInResetFunction, true);
+
+ if (!dispatchEvent(Event::create(eventNames().resetEvent, true, true)))
return;
- }
- for (auto& associatedElement : m_associatedElements) {
- if (is<HTMLFormControlElement>(*associatedElement))
- downcast<HTMLFormControlElement>(*associatedElement).reset();
+ resetAssociatedFormControlElements();
+}
+
+void HTMLFormElement::resetAssociatedFormControlElements()
+{
+ // Event handling can cause associated elements to be added or deleted while iterating
+ // over this collection. Protect these elements until we are done notifying them of
+ // the reset operation.
+ Vector<Ref<HTMLFormControlElement>> associatedFormControlElements;
+ associatedFormControlElements.reserveInitialCapacity(m_associatedElements.size());
+ for (auto* element : m_associatedElements) {
+ if (is<HTMLFormControlElement>(element))
+ associatedFormControlElements.uncheckedAppend(*downcast<HTMLFormControlElement>(element));
}
-
- m_isInResetFunction = false;
+
+ for (auto& associatedFormControlElement : associatedFormControlElements)
+ associatedFormControlElement->reset();
}
#if ENABLE(IOS_AUTOCORRECT_AND_AUTOCAPITALIZE)
@@ -860,10 +865,9 @@
{
ASSERT(!shouldAutocomplete());
- for (auto& associatedElement : m_associatedElements) {
- if (is<HTMLFormControlElement>(*associatedElement))
- downcast<HTMLFormControlElement>(*associatedElement).reset();
- }
+ Ref<HTMLFormElement> protectedThis(*this);
+
+ resetAssociatedFormControlElements();
}
void HTMLFormElement::didMoveToNewDocument(Document* oldDocument)
Modified: branches/safari-602-branch/Source/WebCore/html/HTMLFormElement.h (210001 => 210002)
--- branches/safari-602-branch/Source/WebCore/html/HTMLFormElement.h 2016-12-19 23:41:45 UTC (rev 210001)
+++ branches/safari-602-branch/Source/WebCore/html/HTMLFormElement.h 2016-12-20 00:01:36 UTC (rev 210002)
@@ -181,6 +181,8 @@
bool matchesValidPseudoClass() const final;
bool matchesInvalidPseudoClass() const final;
+ void resetAssociatedFormControlElements();
+
typedef HashMap<RefPtr<AtomicStringImpl>, FormNamedItem*> PastNamesMap;
FormSubmission::Attributes m_attributes;
@@ -189,19 +191,19 @@
RadioButtonGroups m_radioButtonGroups;
mutable HTMLFormControlElement* m_defaultButton { nullptr };
- unsigned m_associatedElementsBeforeIndex;
- unsigned m_associatedElementsAfterIndex;
+ unsigned m_associatedElementsBeforeIndex { 0 };
+ unsigned m_associatedElementsAfterIndex { 0 };
Vector<FormAssociatedElement*> m_associatedElements;
Vector<HTMLImageElement*> m_imageElements;
HashSet<const HTMLFormControlElement*> m_invalidAssociatedFormControls;
- bool m_wasUserSubmitted;
- bool m_isSubmittingOrPreparingForSubmission;
- bool m_shouldSubmit;
+ bool m_wasUserSubmitted { false };
+ bool m_isSubmittingOrPreparingForSubmission { false };
+ bool m_shouldSubmit { false };
- bool m_isInResetFunction;
+ bool m_isInResetFunction { false };
- bool m_wasDemoted;
+ bool m_wasDemoted { false };
#if ENABLE(REQUEST_AUTOCOMPLETE)
void requestAutocompleteTimerFired();