Changeset 266269 in webkit
- Timestamp:
- Aug 27, 2020, 7:55:21 PM (6 years ago)
- Location:
- trunk
- Files:
-
- 12 edited
-
LayoutTests/ChangeLog (modified) (1 diff)
-
LayoutTests/TestExpectations (modified) (1 diff)
-
LayoutTests/imported/w3c/ChangeLog (modified) (1 diff)
-
LayoutTests/imported/w3c/web-platform-tests/custom-elements/upgrading-expected.txt (modified) (1 diff)
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/bindings/js/JSCustomElementInterface.cpp (modified) (6 diffs)
-
Source/WebCore/dom/CustomElementReactionQueue.cpp (modified) (2 diffs)
-
Source/WebCore/dom/CustomElementReactionQueue.h (modified) (2 diffs)
-
Source/WebCore/dom/CustomElementRegistry.cpp (modified) (2 diffs)
-
Source/WebCore/dom/Document.cpp (modified) (1 diff)
-
Source/WebCore/dom/Element.cpp (modified) (5 diffs)
-
Source/WebCore/dom/Element.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r266264 r266269 1 2020-08-27 Ryosuke Niwa <rniwa@webkit.org> 2 3 Prevent infinite recursion when upgrading custom elements 4 https://bugs.webkit.org/show_bug.cgi?id=206605 5 6 Reviewed by Antti Koivisto. 7 8 Removed the crash expectation from a test now that it's passing. 9 10 * TestExpectations: 11 1 12 2020-08-27 Alexey Shvayka <shvaikalesh@gmail.com> 2 13 -
trunk/LayoutTests/TestExpectations
r266186 r266269 568 568 569 569 # Newly imported WPT tests that are crashing. 570 [ Debug ] imported/w3c/web-platform-tests/custom-elements/upgrading.html [ Crash ]571 570 imported/w3c/web-platform-tests/html/semantics/embedded-content/the-embed-element/embed-represent-nothing-04.html [ ImageOnlyFailure Crash ] 572 571 -
trunk/LayoutTests/imported/w3c/ChangeLog
r266261 r266269 1 2020-08-27 Ryosuke Niwa <rniwa@webkit.org> 2 3 Prevent infinite recursion when upgrading custom elements 4 https://bugs.webkit.org/show_bug.cgi?id=206605 5 6 Reviewed by Antti Koivisto. 7 8 Rebaselined the test now that one more test case is passing. 9 10 * web-platform-tests/custom-elements/upgrading-expected.txt: 11 1 12 2020-08-27 Chris Dumez <cdumez@apple.com> 2 13 -
trunk/LayoutTests/imported/w3c/web-platform-tests/custom-elements/upgrading-expected.txt
r264020 r266269 27 27 FAIL If definition's disable shadow is true and element's shadow root is non-null, then throw a "NotSupportedError" DOMException. assert_false: Upgrading should fail. expected false got true 28 28 PASS Infinite constructor recursion with upgrade(this) should not be possible 29 FAIL Infinite constructor recursion with appendChild should not be possible assert_array_equals: expected property 0 to be Element node <infinite-cloning-element-2 id="b"></infinite-cloning-ele... but got Element node <infinite-cloning-element-2 id="a"></infinite-cloning-ele... (expected array [Element node <infinite-cloning-element-2 id="b"></infinite-cloning-ele..., "begin"] got [Element node <infinite-cloning-element-2 id="a"></infinite-cloning-ele..., "end"]) 29 PASS Infinite constructor recursion with appendChild should not be possible 30 30 -
trunk/Source/WebCore/ChangeLog
r266268 r266269 1 2020-08-27 Ryosuke Niwa <rniwa@webkit.org> 2 3 Prevent infinite recursion when upgrading custom elements 4 https://bugs.webkit.org/show_bug.cgi?id=206605 5 6 Reviewed by Antti Koivisto. 7 8 This patch updates our implementation of the concept to upgrade an element [1] and related algorithms 9 to match the latest HTML5 specification. In particular, it incorporates the algorithmic change [2] to 10 prevent infinite recursion an element is re-inserted into a document tree inside its constructor. 11 12 The key code change is in JSCustomElementInterface::upgradeElement where this patch adds an early exit 13 when custom element is not "undefined" or "uncustomized" and the custom element state is set to "failed" 14 immediately before invoking the constructor. The rest of code changes deals with this "failed" state 15 appearing during upgrades and updates various debug assertions. 16 17 [1] https://html.spec.whatwg.org/multipage/custom-elements.html#concept-upgrade-an-element 18 [2] https://github.com/whatwg/html/pull/5126 19 [3] https://html.spec.whatwg.org/multipage/custom-elements.html#concept-try-upgrade 20 21 Test: imported/w3c/web-platform-tests/custom-elements/upgrading.html 22 23 * bindings/js/JSCustomElementInterface.cpp: 24 (WebCore::JSCustomElementInterface::constructElementWithFallback): 25 (WebCore::JSCustomElementInterface::upgradeElement): Implements the new behavior. Note that we still 26 need to clear the queue where we used to set the custom element state to "failed" to avoid memory leaks. 27 * dom/CustomElementReactionQueue.cpp: 28 (WebCore::CustomElementReactionQueue::hasJustUpgradeReaction const): Added. 29 (WebCore::CustomElementReactionQueue::enqueueElementUpgrade): Enqueue the element to the element queue 30 even if it had already been scheduled to upgrade previously. This makes the innermost attempt to upgrade 31 to succeed instead of the outermost. Also updated debug assertions. 32 (WebCore::CustomElementReactionQueue::tryToUpgradeElement): Renamed from enqueueElementUpgradeIfDefined 33 to match the spec's name [3]. Unlike the concept in the spec, this function doesn't get called when 34 the custom element state of the elemnt is either "undefined" or "uncustomized" to avoid unnecessary work. 35 * dom/CustomElementReactionQueue.h: 36 (WebCore::CustomElementReactionQueue::isEmpty const): Added. 37 * dom/CustomElementRegistry.cpp: 38 (WebCore::upgradeElementsInShadowIncludingDescendants): 39 (WebCore::CustomElementRegistry::upgrade): 40 * dom/Document.cpp: 41 (WebCore::createFallbackHTMLElement): Call setIsCustomElementUpgradeCandidate on a newly created since 42 we can no longer update node flags in enqueueToUpgrade 43 * dom/Element.cpp: 44 (WebCore::Element::insertedIntoAncestor): 45 (WebCore::Element::setIsFailedCustomElement): Removed the unused function argument. 46 (WebCore::Element::setIsFailedCustomElementWithoutClearingReactionQueue): Extracted from 47 setIsFailedCustomElement. 48 (WebCore::Element::clearReactionQueueFromFailedCustomElement): Ditto. 49 (WebCore::Element::enqueueToUpgrade): No longer updates node flags as this would clear "failed" state 50 from a custom element which is currently being upgraded and cause all sorts of issues. 51 (WebCore::Element::reactionQueue const): Updated debug assertions. 52 * dom/Element.h: 53 1 54 2020-08-27 John Wilander <wilander@apple.com> 2 55 -
trunk/Source/WebCore/bindings/js/JSCustomElementInterface.cpp
r260744 r266269 65 65 auto element = HTMLUnknownElement::create(QualifiedName(nullAtom(), localName, HTMLNames::xhtmlNamespaceURI), document); 66 66 element->setIsCustomElementUpgradeCandidate(); 67 element->setIsFailedCustomElement( *this);67 element->setIsFailedCustomElement(); 68 68 69 69 return element; … … 80 80 auto element = HTMLUnknownElement::create(name, document); 81 81 element->setIsCustomElementUpgradeCandidate(); 82 element->setIsFailedCustomElement( *this);82 element->setIsFailedCustomElement(); 83 83 84 84 return element; … … 163 163 } 164 164 165 // https://html.spec.whatwg.org/multipage/custom-elements.html#concept-upgrade-an-element 165 166 void JSCustomElementInterface::upgradeElement(Element& element) 166 167 { 167 168 ASSERT(element.tagQName() == name()); 169 170 if (element.isDefinedCustomElement() || element.isFailedCustomElement()) 171 return; // If element's custom element state is not "undefined" or "uncustomized", then return. 172 168 173 ASSERT(element.isCustomElementUpgradeCandidate()); 169 174 if (!canInvokeCallback()) … … 193 198 194 199 CustomElementReactionQueue::enqueuePostUpgradeReactions(element); 200 201 // Unlike spec, set element's custom element state to "failed" after enqueueing post-upgrade reactions 202 // to avoid hitting debug assertions in enqueuePostUpgradeReactions. 203 element.setIsFailedCustomElementWithoutClearingReactionQueue(); 195 204 196 205 m_constructionStack.append(&element); … … 205 214 206 215 if (UNLIKELY(scope.exception())) { 207 element. setIsFailedCustomElement(*this);216 element.clearReactionQueueFromFailedCustomElement(); 208 217 reportException(lexicalGlobalObject, scope.exception()); 209 218 return; … … 212 221 Element* wrappedElement = JSElement::toWrapped(vm, returnedElement); 213 222 if (!wrappedElement || wrappedElement != &element) { 214 element. setIsFailedCustomElement(*this);223 element.clearReactionQueueFromFailedCustomElement(); 215 224 reportException(lexicalGlobalObject, createDOMException(lexicalGlobalObject, TypeError, "Custom element constructor returned a wrong element")); 216 225 return; -
trunk/Source/WebCore/dom/CustomElementReactionQueue.cpp
r254087 r266269 119 119 } 120 120 121 #if ASSERT_ENABLED 122 bool CustomElementReactionQueue::hasJustUpgradeReaction() const 123 { 124 return m_items.size() == 1 && m_items[0].type() == CustomElementReactionQueueItem::Type::ElementUpgrade; 125 } 126 #endif 127 121 128 void CustomElementReactionQueue::enqueueElementUpgrade(Element& element, bool alreadyScheduledToUpgrade) 122 129 { … … 124 131 ASSERT(element.reactionQueue()); 125 132 auto& queue = *element.reactionQueue(); 126 if (alreadyScheduledToUpgrade) { 127 ASSERT(queue.m_items.size() == 1); 128 ASSERT(queue.m_items[0].type() == CustomElementReactionQueueItem::Type::ElementUpgrade); 129 } else { 133 if (alreadyScheduledToUpgrade) 134 ASSERT(queue.hasJustUpgradeReaction()); 135 else 130 136 queue.m_items.append({CustomElementReactionQueueItem::Type::ElementUpgrade}); 131 enqueueElementOnAppropriateElementQueue(element);132 }133 } 134 135 void CustomElementReactionQueue:: enqueueElementUpgradeIfDefined(Element& element)137 enqueueElementOnAppropriateElementQueue(element); 138 } 139 140 // https://html.spec.whatwg.org/multipage/custom-elements.html#concept-try-upgrade 141 void CustomElementReactionQueue::tryToUpgradeElement(Element& element) 136 142 { 137 143 ASSERT(CustomElementReactionDisallowedScope::isReactionAllowed()); -
trunk/Source/WebCore/dom/CustomElementReactionQueue.h
r254087 r266269 71 71 72 72 static void enqueueElementUpgrade(Element&, bool alreadyScheduledToUpgrade); 73 static void enqueueElementUpgradeIfDefined(Element&);73 static void tryToUpgradeElement(Element&); 74 74 static void enqueueConnectedCallbackIfNeeded(Element&); 75 75 static void enqueueDisconnectedCallbackIfNeeded(Element&); … … 81 81 void invokeAll(Element&); 82 82 void clear(); 83 bool isEmpty() const { return m_items.isEmpty(); } 84 #if ASSERT_ENABLED 85 bool hasJustUpgradeReaction() const; 86 #endif 83 87 84 88 static void processBackupQueue(CustomElementQueue&); -
trunk/Source/WebCore/dom/CustomElementRegistry.cpp
r266157 r266269 118 118 for (auto& element : descendantsOfType<Element>(root)) { 119 119 if (element.isCustomElementUpgradeCandidate()) 120 CustomElementReactionQueue:: enqueueElementUpgradeIfDefined(element);120 CustomElementReactionQueue::tryToUpgradeElement(element); 121 121 if (auto* shadowRoot = element.shadowRoot()) 122 122 upgradeElementsInShadowIncludingDescendants(*shadowRoot); … … 130 130 131 131 if (is<Element>(root) && downcast<Element>(root).isCustomElementUpgradeCandidate()) 132 CustomElementReactionQueue:: enqueueElementUpgradeIfDefined(downcast<Element>(root));132 CustomElementReactionQueue::tryToUpgradeElement(downcast<Element>(root)); 133 133 134 134 upgradeElementsInShadowIncludingDescendants(downcast<ContainerNode>(root)); -
trunk/Source/WebCore/dom/Document.cpp
r265782 r266269 1152 1152 if (auto* elementInterface = registry->findInterface(name)) { 1153 1153 auto element = HTMLElement::create(name, document); 1154 element->setIsCustomElementUpgradeCandidate(); 1154 1155 element->enqueueToUpgrade(*elementInterface); 1155 1156 return element; -
trunk/Source/WebCore/dom/Element.cpp
r265820 r266269 2174 2174 if (UNLIKELY(isCustomElementUpgradeCandidate())) { 2175 2175 ASSERT(isConnected()); 2176 CustomElementReactionQueue:: enqueueElementUpgradeIfDefined(*this);2176 CustomElementReactionQueue::tryToUpgradeElement(*this); 2177 2177 } 2178 2178 if (UNLIKELY(isDefinedCustomElement())) … … 2414 2414 } 2415 2415 2416 void Element::setIsFailedCustomElement(JSCustomElementInterface&) 2416 void Element::setIsFailedCustomElement() 2417 { 2418 setIsFailedCustomElementWithoutClearingReactionQueue(); 2419 clearReactionQueueFromFailedCustomElement(); 2420 } 2421 2422 void Element::setIsFailedCustomElementWithoutClearingReactionQueue() 2417 2423 { 2418 2424 ASSERT(isUndefinedCustomElement()); 2419 2425 ASSERT(getFlag(IsEditingTextOrUndefinedCustomElementFlag)); 2420 2426 clearFlag(IsCustomElement); 2421 2427 InspectorInstrumentation::didChangeCustomElementState(*this); 2428 } 2429 2430 void Element::clearReactionQueueFromFailedCustomElement() 2431 { 2432 ASSERT(isFailedCustomElement()); 2422 2433 if (hasRareData()) { 2423 2434 // Clear the queue instead of deleting it since this function can be called inside CustomElementReactionQueue::invokeAll during upgrades. … … 2425 2436 queue->clear(); 2426 2437 } 2427 InspectorInstrumentation::didChangeCustomElementState(*this);2428 2438 } 2429 2439 … … 2438 2448 void Element::enqueueToUpgrade(JSCustomElementInterface& elementInterface) 2439 2449 { 2450 ASSERT(isCustomElementUpgradeCandidate()); 2440 2451 ASSERT(!isDefinedCustomElement() && !isFailedCustomElement()); 2441 setFlag(IsCustomElement);2442 setFlag(IsEditingTextOrUndefinedCustomElementFlag);2443 InspectorInstrumentation::didChangeCustomElementState(*this);2444 2445 2452 auto& data = ensureElementRareData(); 2446 2453 bool alreadyScheduledToUpgrade = data.customElementReactionQueue(); … … 2452 2459 CustomElementReactionQueue* Element::reactionQueue() const 2453 2460 { 2454 ASSERT(isDefinedCustomElement() || isCustomElementUpgradeCandidate()); 2461 #if ASSERT_ENABLED 2462 if (isFailedCustomElement()) { 2463 auto* queue = elementRareData()->customElementReactionQueue(); 2464 ASSERT(queue); 2465 ASSERT(queue->isEmpty() || queue->hasJustUpgradeReaction()); 2466 } else 2467 ASSERT(isDefinedCustomElement() || isCustomElementUpgradeCandidate()); 2468 #endif 2455 2469 if (!hasRareData()) 2456 2470 return nullptr; -
trunk/Source/WebCore/dom/Element.h
r265092 r266269 304 304 305 305 void setIsDefinedCustomElement(JSCustomElementInterface&); 306 void setIsFailedCustomElement(JSCustomElementInterface&); 306 void setIsFailedCustomElement(); 307 void setIsFailedCustomElementWithoutClearingReactionQueue(); 308 void clearReactionQueueFromFailedCustomElement(); 307 309 void setIsCustomElementUpgradeCandidate(); 308 310 void enqueueToUpgrade(JSCustomElementInterface&);
Note:
See TracChangeset
for help on using the changeset viewer.