Title: [276404] branches/safari-611-branch/Source/WebCore
Revision
276404
Author
[email protected]
Date
2021-04-21 16:39:33 -0700 (Wed, 21 Apr 2021)

Log Message

Cherry-pick r276010. rdar://problem/76962988

    Integrator's note, used bit 27 instead of 26 to avoid conflict.

    REGRESSION(r272900): Nullptr crash in ComposedTreeIterator::traverseNextInShadowTree() via ShadowRoot::hostChildElementDidChange
    https://bugs.webkit.org/show_bug.cgi?id=222720

    Patch by Carlos Garcia Campos <[email protected]> on 2021-04-15
    Reviewed by Ryosuke Niwa.

    This patch reverts r274064 to apply a different fix. Instead of null-checking the nodes returned by
    SlotAssignment::assignedNodesForSlot(), assigned nodes are removed from the list when they are about to be
    removed from the parent. That ensures we never return nullptr nodes nor nodes with a nullptr parent from the
    assigned nodes vector.

    * dom/ComposedTreeIterator.cpp:
    (WebCore::ComposedTreeIterator::traverseNextInShadowTree):
    (WebCore::ComposedTreeIterator::advanceInSlot):
    * dom/ContainerNode.cpp:
    (WebCore::ContainerNode::removeBetween):
    * dom/Node.h:
    (WebCore::Node::hasShadowRootContainingSlots const):
    (WebCore::Node::setHasShadowRootContainingSlots):
    * dom/ShadowRoot.h:
    * dom/SlotAssignment.cpp:
    (WebCore::SlotAssignment::addSlotElementByName):
    (WebCore::SlotAssignment::removeSlotElementByName):
    (WebCore::SlotAssignment::willRemoveAssignedNode):
    * dom/SlotAssignment.h:
    (WebCore::ShadowRoot::willRemoveAssignedNode):

    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@276010 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Modified Paths

Diff

Modified: branches/safari-611-branch/Source/WebCore/ChangeLog (276403 => 276404)


--- branches/safari-611-branch/Source/WebCore/ChangeLog	2021-04-21 23:39:29 UTC (rev 276403)
+++ branches/safari-611-branch/Source/WebCore/ChangeLog	2021-04-21 23:39:33 UTC (rev 276404)
@@ -1,5 +1,66 @@
 2021-04-21  Ruben Turcios  <[email protected]>
 
+        Cherry-pick r276010. rdar://problem/76962988
+
+    REGRESSION(r272900): Nullptr crash in ComposedTreeIterator::traverseNextInShadowTree() via ShadowRoot::hostChildElementDidChange
+    https://bugs.webkit.org/show_bug.cgi?id=222720
+    
+    Patch by Carlos Garcia Campos <[email protected]> on 2021-04-15
+    Reviewed by Ryosuke Niwa.
+    
+    This patch reverts r274064 to apply a different fix. Instead of null-checking the nodes returned by
+    SlotAssignment::assignedNodesForSlot(), assigned nodes are removed from the list when they are about to be
+    removed from the parent. That ensures we never return nullptr nodes nor nodes with a nullptr parent from the
+    assigned nodes vector.
+    
+    * dom/ComposedTreeIterator.cpp:
+    (WebCore::ComposedTreeIterator::traverseNextInShadowTree):
+    (WebCore::ComposedTreeIterator::advanceInSlot):
+    * dom/ContainerNode.cpp:
+    (WebCore::ContainerNode::removeBetween):
+    * dom/Node.h:
+    (WebCore::Node::hasShadowRootContainingSlots const):
+    (WebCore::Node::setHasShadowRootContainingSlots):
+    * dom/ShadowRoot.h:
+    * dom/SlotAssignment.cpp:
+    (WebCore::SlotAssignment::addSlotElementByName):
+    (WebCore::SlotAssignment::removeSlotElementByName):
+    (WebCore::SlotAssignment::willRemoveAssignedNode):
+    * dom/SlotAssignment.h:
+    (WebCore::ShadowRoot::willRemoveAssignedNode):
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@276010 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2021-04-15  Carlos Garcia Campos  <[email protected]>
+
+            REGRESSION(r272900): Nullptr crash in ComposedTreeIterator::traverseNextInShadowTree() via ShadowRoot::hostChildElementDidChange
+            https://bugs.webkit.org/show_bug.cgi?id=222720
+
+            Reviewed by Ryosuke Niwa.
+
+            This patch reverts r274064 to apply a different fix. Instead of null-checking the nodes returned by
+            SlotAssignment::assignedNodesForSlot(), assigned nodes are removed from the list when they are about to be
+            removed from the parent. That ensures we never return nullptr nodes nor nodes with a nullptr parent from the
+            assigned nodes vector.
+
+            * dom/ComposedTreeIterator.cpp:
+            (WebCore::ComposedTreeIterator::traverseNextInShadowTree):
+            (WebCore::ComposedTreeIterator::advanceInSlot):
+            * dom/ContainerNode.cpp:
+            (WebCore::ContainerNode::removeBetween):
+            * dom/Node.h:
+            (WebCore::Node::hasShadowRootContainingSlots const):
+            (WebCore::Node::setHasShadowRootContainingSlots):
+            * dom/ShadowRoot.h:
+            * dom/SlotAssignment.cpp:
+            (WebCore::SlotAssignment::addSlotElementByName):
+            (WebCore::SlotAssignment::removeSlotElementByName):
+            (WebCore::SlotAssignment::willRemoveAssignedNode):
+            * dom/SlotAssignment.h:
+            (WebCore::ShadowRoot::willRemoveAssignedNode):
+
+2021-04-21  Ruben Turcios  <[email protected]>
+
         Cherry-pick r276206. rdar://problem/76962916
 
     Perform port blocking earlier in the load

Modified: branches/safari-611-branch/Source/WebCore/dom/ComposedTreeIterator.cpp (276403 => 276404)


--- branches/safari-611-branch/Source/WebCore/dom/ComposedTreeIterator.cpp	2021-04-21 23:39:29 UTC (rev 276403)
+++ branches/safari-611-branch/Source/WebCore/dom/ComposedTreeIterator.cpp	2021-04-21 23:39:33 UTC (rev 276404)
@@ -162,11 +162,12 @@
     if (is<HTMLSlotElement>(current())) {
         auto& slot = downcast<HTMLSlotElement>(current());
         if (auto* assignedNodes = slot.assignedNodes()) {
-            if (auto assignedNode = assignedNodes->at(0)) {
-                context().slotNodeIndex = 0;
-                m_contextStack.append(Context(*assignedNode->parentElement(), *assignedNode, Context::Slotted));
-                return;
-            }
+            context().slotNodeIndex = 0;
+            auto* assignedNode = assignedNodes->at(0).get();
+            ASSERT(assignedNode);
+            ASSERT(assignedNode->parentElement());
+            m_contextStack.append(Context(*assignedNode->parentElement(), *assignedNode, Context::Slotted));
+            return;
         }
     }
 
@@ -199,8 +200,8 @@
         return false;
 
     auto* slotNode = assignedNodes.at(context().slotNodeIndex).get();
-    if (!slotNode)
-        return false;
+    ASSERT(slotNode);
+    ASSERT(slotNode->parentElement());
     m_contextStack.append(Context(*slotNode->parentElement(), *slotNode, Context::Slotted));
     return true;
 }

Modified: branches/safari-611-branch/Source/WebCore/dom/ContainerNode.cpp (276403 => 276404)


--- branches/safari-611-branch/Source/WebCore/dom/ContainerNode.cpp	2021-04-21 23:39:29 UTC (rev 276403)
+++ branches/safari-611-branch/Source/WebCore/dom/ContainerNode.cpp	2021-04-21 23:39:33 UTC (rev 276404)
@@ -630,6 +630,9 @@
 
     destroyRenderTreeIfNeeded(oldChild);
 
+    if (UNLIKELY(hasShadowRootContainingSlots()))
+        shadowRoot()->willRemoveAssignedNode(oldChild);
+
     if (nextChild) {
         nextChild->setPreviousSibling(previousChild);
         oldChild.setNextSibling(nullptr);

Modified: branches/safari-611-branch/Source/WebCore/dom/Node.h (276403 => 276404)


--- branches/safari-611-branch/Source/WebCore/dom/Node.h	2021-04-21 23:39:29 UTC (rev 276403)
+++ branches/safari-611-branch/Source/WebCore/dom/Node.h	2021-04-21 23:39:33 UTC (rev 276404)
@@ -226,6 +226,9 @@
     bool hasSyntheticAttrChildNodes() const { return hasNodeFlag(NodeFlag::HasSyntheticAttrChildNodes); }
     void setHasSyntheticAttrChildNodes(bool flag) { setNodeFlag(NodeFlag::HasSyntheticAttrChildNodes, flag); }
 
+    bool hasShadowRootContainingSlots() const { return hasNodeFlag(NodeFlag::HasShadowRootContainingSlots); }
+    void setHasShadowRootContainingSlots(bool flag) { setNodeFlag(NodeFlag::HasShadowRootContainingSlots, flag); }
+
     // If this node is in a shadow tree, returns its shadow host. Otherwise, returns null.
     WEBCORE_EXPORT Element* shadowHost() const;
     ShadowRoot* containingShadowRoot() const;
@@ -558,7 +561,9 @@
 #endif
         IsComputedStyleInvalidFlag = 1 << 26,
 
-        // Bits 27-31 are free.
+        HasShadowRootContainingSlots = 1 << 27,
+
+        // Bits 28-31 are free.
     };
 
     enum class TabIndexState : uint8_t {

Modified: branches/safari-611-branch/Source/WebCore/dom/ShadowRoot.h (276403 => 276404)


--- branches/safari-611-branch/Source/WebCore/dom/ShadowRoot.h	2021-04-21 23:39:29 UTC (rev 276403)
+++ branches/safari-611-branch/Source/WebCore/dom/ShadowRoot.h	2021-04-21 23:39:33 UTC (rev 276404)
@@ -93,6 +93,7 @@
     void slotFallbackDidChange(HTMLSlotElement&);
     void resolveSlotsBeforeNodeInsertionOrRemoval();
     void willRemoveAllChildren(ContainerNode&);
+    void willRemoveAssignedNode(const Node&);
 
     void didRemoveAllChildrenOfShadowHost();
     void didChangeDefaultSlot();

Modified: branches/safari-611-branch/Source/WebCore/dom/SlotAssignment.cpp (276403 => 276404)


--- branches/safari-611-branch/Source/WebCore/dom/SlotAssignment.cpp	2021-04-21 23:39:29 UTC (rev 276403)
+++ branches/safari-611-branch/Source/WebCore/dom/SlotAssignment.cpp	2021-04-21 23:39:33 UTC (rev 276404)
@@ -124,6 +124,9 @@
     if (!m_slotAssignmentsIsValid)
         assignSlots(shadowRoot);
 
+    shadowRoot.host()->setHasShadowRootContainingSlots(true);
+    m_slotElementCount++;
+
     bool needsSlotchangeEvent = shadowRoot.shouldFireSlotchangeEvent() && hasAssignedNodes(shadowRoot, slot);
 
     slot.elementCount++;
@@ -151,8 +154,15 @@
     m_slotElementsForConsistencyCheck.remove(&slotElement);
 #endif
 
-    if (auto* host = shadowRoot.host()) // FIXME: We should be able to do a targeted reconstruction.
+    ASSERT(m_slotElementCount > 0);
+    m_slotElementCount--;
+
+    if (auto host = makeRefPtr(shadowRoot.host())) {
+        // FIXME: We should be able to do a targeted reconstruction.
         host->invalidateStyleAndRenderersForSubtree();
+        if (!m_slotElementCount)
+            host->setHasShadowRootContainingSlots(false);
+    }
 
     auto* slot = m_slots.get(slotNameFromAttributeValue(name));
     RELEASE_ASSERT(slot && slot->hasSlotElements());
@@ -337,6 +347,23 @@
     return &slot->assignedNodes;
 }
 
+void SlotAssignment::willRemoveAssignedNode(const Node& node)
+{
+    if (!m_slotAssignmentsIsValid)
+        return;
+
+    if (!is<Text>(node) && !is<Element>(node))
+        return;
+
+    auto* slot = m_slots.get(slotNameForHostChild(node));
+    if (!slot || slot->assignedNodes.isEmpty())
+        return;
+
+    slot->assignedNodes.removeFirstMatching([&node](const auto& item) {
+        return item.get() == &node;
+    });
+}
+
 const AtomString& SlotAssignment::slotNameForHostChild(const Node& child) const
 {
     return slotNameFromSlotAttribute(child);

Modified: branches/safari-611-branch/Source/WebCore/dom/SlotAssignment.h (276403 => 276404)


--- branches/safari-611-branch/Source/WebCore/dom/SlotAssignment.h	2021-04-21 23:39:29 UTC (rev 276403)
+++ branches/safari-611-branch/Source/WebCore/dom/SlotAssignment.h	2021-04-21 23:39:33 UTC (rev 276404)
@@ -61,6 +61,7 @@
     void enqueueSlotChangeEvent(const AtomString&, ShadowRoot&);
 
     const Vector<WeakPtr<Node>>* assignedNodesForSlot(const HTMLSlotElement&, ShadowRoot&);
+    void willRemoveAssignedNode(const Node&);
 
     virtual void hostChildElementDidChange(const Element&, ShadowRoot&);
 
@@ -104,6 +105,7 @@
     bool m_willBeRemovingAllChildren { false };
     unsigned m_slotMutationVersion { 0 };
     unsigned m_slotResolutionVersion { 0 };
+    unsigned m_slotElementCount { 0 };
 };
 
 inline void ShadowRoot::resolveSlotsBeforeNodeInsertionOrRemoval()
@@ -145,4 +147,10 @@
     RenderTreeUpdater::tearDownRenderers(element);
 }
 
+inline void ShadowRoot::willRemoveAssignedNode(const Node& node)
+{
+    if (m_slotAssignment)
+        m_slotAssignment->willRemoveAssignedNode(node);
+}
+
 } // namespace WebCore
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to