Changeset 226095 in webkit
- Timestamp:
- Dec 18, 2017 8:32:43 PM (6 years ago)
- Location:
- trunk
- Files:
-
- 4 added
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r226090 r226095 1 2017-12-18 Ryosuke Niwa <rniwa@webkit.org> 2 3 Assertion hit in DocumentOrderedMap::get while removing a form element 4 https://bugs.webkit.org/show_bug.cgi?id=137959 5 <rdar://problem/27702012> 6 7 Reviewed by Brent Fulgham. 8 9 Added regression tests for removing a subtree with a form associated element, its owner form element 10 and another element with the same ID. 11 12 * fast/forms/update-form-owner-in-moved-subtree-assertion-failure-5-expected.txt: Added. 13 * fast/forms/update-form-owner-in-moved-subtree-assertion-failure-5.html: Added. 14 * fast/forms/update-form-owner-in-moved-subtree-assertion-failure-6-expected.txt: Added. 15 * fast/forms/update-form-owner-in-moved-subtree-assertion-failure-6.html: Added. 16 1 17 2017-12-18 Youenn Fablet <youenn@apple.com> 2 18 -
trunk/Source/WebCore/ChangeLog
r226094 r226095 1 2017-12-18 Ryosuke Niwa <rniwa@webkit.org> 2 3 Assertion hit in DocumentOrderedMap::get while removing a form element 4 https://bugs.webkit.org/show_bug.cgi?id=137959 5 <rdar://problem/27702012> 6 7 Reviewed by Brent Fulgham. 8 9 The assertion failure was caused by FormAssociatedElement::findAssociatedForm calling TreeScope::getElementById 10 for a form associated element inside FormAttributeTargetObserver::idTargetChanged during the removal of 11 the owner form element, or the first non-form element with the matching ID. If there are other elements with 12 the same ID in the removed tree at that moment, MapEntry's count for the ID can be higher than it needs to be 13 since Element::removedFromAncestor has not been called on those elements yet. 14 15 Fixed the bug by checking this condition explicitly. This patch introduces ContainerChildRemovalScope which 16 keeps track of the container node from which a subtree was removed as well as the root of the removed subtree. 17 DocumentOrderedMap::get then checks whether the matching element can be found in this removed subtree, and its 18 isConnected() still returns true (the evidence that Element::removedFromAncestor has not been called) when 19 count > 0 and there was no matching element in the tree scope. 20 21 In the long term, we should refactor the way FormAssociatedElement and HTMLFormElement refers to each other 22 and avoid calling DocumentOrderedMap::get before finish calling removedFromAncestor on the removed subtree. 23 24 Tests: fast/forms/update-form-owner-in-moved-subtree-assertion-failure-5.html 25 fast/forms/update-form-owner-in-moved-subtree-assertion-failure-6.html 26 27 * dom/ContainerNodeAlgorithms.cpp: 28 (WebCore::notifyChildNodeRemoved): 29 * dom/ContainerNodeAlgorithms.h: 30 (WebCore::ContainerChildRemovalScope): Added. 31 (WebCore::ContainerChildRemovalScope::ContainerChildRemovalScope): 32 (WebCore::ContainerChildRemovalScope::~ContainerChildRemovalScope): 33 (WebCore::ContainerChildRemovalScope::parentOfRemovedTree): 34 (WebCore::ContainerChildRemovalScope::removedChild): 35 (WebCore::ContainerChildRemovalScope::currentScope): 36 * dom/DocumentOrderedMap.cpp: 37 (WebCore::DocumentOrderedMap::get const): Added a special early exit when this function is called during 38 a node removal. 39 1 40 2017-12-18 Timothy Hatcher <timothy@hatcher.name> 2 41 -
trunk/Source/WebCore/dom/ContainerNodeAlgorithms.cpp
r224356 r226095 36 36 namespace WebCore { 37 37 38 #if !ASSERT_DISABLED 39 ContainerChildRemovalScope* ContainerChildRemovalScope::s_scope = nullptr; 40 #endif 41 38 42 enum class TreeScopeChange { Changed, DidNotChange }; 39 43 … … 150 154 // Assert that the caller of this function has an instance of NoEventDispatchAssertion. 151 155 ASSERT(!isMainThread() || !NoEventDispatchAssertion::InMainThread::isEventAllowed()); 156 ContainerChildRemovalScope removalScope(oldParentOfRemovedTree, child); 152 157 153 158 // Tree scope has changed if the container node from which "node" is removed is in a document or a shadow root. -
trunk/Source/WebCore/dom/ContainerNodeAlgorithms.h
r223802 r226095 27 27 namespace WebCore { 28 28 29 // FIXME: Delete this class after fixing FormAssociatedElement to avoid calling getElementById during a tree removal. 30 #if !ASSERT_DISABLED 31 class ContainerChildRemovalScope { 32 public: 33 ContainerChildRemovalScope(ContainerNode& parentOfRemovedTree, Node& child) 34 : m_parentOfRemovedTree(parentOfRemovedTree) 35 , m_removedChild(child) 36 , m_previousScope(s_scope) 37 { 38 s_scope = this; 39 } 40 41 ~ContainerChildRemovalScope() 42 { 43 s_scope = m_previousScope; 44 } 45 46 ContainerNode& parentOfRemovedTree() { return m_parentOfRemovedTree; } 47 Node& removedChild() { return m_removedChild; } 48 49 static ContainerChildRemovalScope* currentScope() { return s_scope; } 50 51 private: 52 ContainerNode& m_parentOfRemovedTree; 53 Node& m_removedChild; 54 ContainerChildRemovalScope* m_previousScope; 55 static ContainerChildRemovalScope* s_scope; 56 }; 57 #else 58 class ContainerChildRemovalScope { 59 public: 60 ContainerChildRemovalScope(ContainerNode&, Node&) { } 61 }; 62 #endif 63 29 64 NodeVector notifyChildNodeInserted(ContainerNode& parentOfInsertedTree, Node&); 30 65 void notifyChildNodeRemoved(ContainerNode& oldParentOfRemovedTree, Node&); -
trunk/Source/WebCore/dom/DocumentOrderedMap.cpp
r223886 r226095 32 32 #include "DocumentOrderedMap.h" 33 33 34 #include "ContainerNodeAlgorithms.h" 34 35 #include "ElementIterator.h" 35 36 #include "HTMLImageElement.h" … … 121 122 return &element; 122 123 } 124 125 #if !ASSERT_DISABLED 126 // FormAssociatedElement may call getElementById to find its owner form in the middle of a tree removal. 127 if (auto* currentScope = ContainerChildRemovalScope::currentScope()) { 128 ASSERT(&scope.rootNode() == ¤tScope->parentOfRemovedTree().rootNode()); 129 Node& removedTree = currentScope->removedChild(); 130 ASSERT(is<ContainerNode>(removedTree)); 131 for (auto& element : descendantsOfType<Element>(downcast<ContainerNode>(removedTree))) { 132 if (!keyMatches(key, element)) 133 continue; 134 bool removedFromAncestorHasNotBeenCalledYet = element.isConnected(); 135 ASSERT(removedFromAncestorHasNotBeenCalledYet); 136 return nullptr; 137 } 138 } 123 139 ASSERT_NOT_REACHED(); 140 #endif 141 124 142 return nullptr; 125 143 }
Note: See TracChangeset
for help on using the changeset viewer.