Changeset 282505 in webkit


Ignore:
Timestamp:
Sep 16, 2021, 1:26:42 AM (4 years ago)
Author:
Adrian Perez de Castro
Message:

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

Patch by Carlos Garcia Campos <cgarcia@igalia.com> 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):

Location:
releases/WebKitGTK/webkit-2.32/Source/WebCore
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • releases/WebKitGTK/webkit-2.32/Source/WebCore/ChangeLog

    r282504 r282505  
     12021-04-15  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        REGRESSION(r272900): Nullptr crash in ComposedTreeIterator::traverseNextInShadowTree() via ShadowRoot::hostChildElementDidChange
     4        https://bugs.webkit.org/show_bug.cgi?id=222720
     5
     6        Reviewed by Ryosuke Niwa.
     7
     8        This patch reverts r274064 to apply a different fix. Instead of null-checking the nodes returned by
     9        SlotAssignment::assignedNodesForSlot(), assigned nodes are removed from the list when they are about to be
     10        removed from the parent. That ensures we never return nullptr nodes nor nodes with a nullptr parent from the
     11        assigned nodes vector.
     12
     13        * dom/ComposedTreeIterator.cpp:
     14        (WebCore::ComposedTreeIterator::traverseNextInShadowTree):
     15        (WebCore::ComposedTreeIterator::advanceInSlot):
     16        * dom/ContainerNode.cpp:
     17        (WebCore::ContainerNode::removeBetween):
     18        * dom/Node.h:
     19        (WebCore::Node::hasShadowRootContainingSlots const):
     20        (WebCore::Node::setHasShadowRootContainingSlots):
     21        * dom/ShadowRoot.h:
     22        * dom/SlotAssignment.cpp:
     23        (WebCore::SlotAssignment::addSlotElementByName):
     24        (WebCore::SlotAssignment::removeSlotElementByName):
     25        (WebCore::SlotAssignment::willRemoveAssignedNode):
     26        * dom/SlotAssignment.h:
     27        (WebCore::ShadowRoot::willRemoveAssignedNode):
     28
    1292021-04-14  Ryosuke Niwa  <rniwa@webkit.org>
    230
  • releases/WebKitGTK/webkit-2.32/Source/WebCore/dom/ComposedTreeIterator.cpp

    r280832 r282505  
    163163        auto& slot = downcast<HTMLSlotElement>(current());
    164164        if (auto* assignedNodes = slot.assignedNodes()) {
    165             if (auto assignedNode = assignedNodes->at(0)) {
    166                 context().slotNodeIndex = 0;
    167                 m_contextStack.append(Context(*assignedNode->parentElement(), *assignedNode, Context::Slotted));
    168                 return;
    169             }
     165            context().slotNodeIndex = 0;
     166            auto* assignedNode = assignedNodes->at(0).get();
     167            ASSERT(assignedNode);
     168            ASSERT(assignedNode->parentElement());
     169            m_contextStack.append(Context(*assignedNode->parentElement(), *assignedNode, Context::Slotted));
     170            return;
    170171        }
    171172    }
     
    200201
    201202    auto* slotNode = assignedNodes.at(context().slotNodeIndex).get();
    202     if (!slotNode)
    203         return false;
     203    ASSERT(slotNode);
     204    ASSERT(slotNode->parentElement());
    204205    m_contextStack.append(Context(*slotNode->parentElement(), *slotNode, Context::Slotted));
    205206    return true;
  • releases/WebKitGTK/webkit-2.32/Source/WebCore/dom/ContainerNode.cpp

    r280835 r282505  
    631631    destroyRenderTreeIfNeeded(oldChild);
    632632
     633    if (UNLIKELY(hasShadowRootContainingSlots()))
     634        shadowRoot()->willRemoveAssignedNode(oldChild);
     635
    633636    if (nextChild) {
    634637        nextChild->setPreviousSibling(previousChild);
  • releases/WebKitGTK/webkit-2.32/Source/WebCore/dom/Node.h

    r280901 r282505  
    223223    void setHasSyntheticAttrChildNodes(bool flag) { setNodeFlag(NodeFlag::HasSyntheticAttrChildNodes, flag); }
    224224
     225    bool hasShadowRootContainingSlots() const { return hasNodeFlag(NodeFlag::HasShadowRootContainingSlots); }
     226    void setHasShadowRootContainingSlots(bool flag) { setNodeFlag(NodeFlag::HasShadowRootContainingSlots, flag); }
     227
    225228    // If this node is in a shadow tree, returns its shadow host. Otherwise, returns null.
    226229    WEBCORE_EXPORT Element* shadowHost() const;
     
    567570        InclusiveAncestorStateForForm = 1 << 28,
    568571        InclusiveAncestorStateForCanvas = 1 << 29,
    569         // Bits 30-31 are free.
     572        HasShadowRootContainingSlots = 1 << 30,
     573        // Bit 31 is free.
    570574    };
    571575
  • releases/WebKitGTK/webkit-2.32/Source/WebCore/dom/ShadowRoot.h

    r266212 r282505  
    9494    void resolveSlotsBeforeNodeInsertionOrRemoval();
    9595    void willRemoveAllChildren(ContainerNode&);
     96    void willRemoveAssignedNode(const Node&);
    9697
    9798    void didRemoveAllChildrenOfShadowHost();
  • releases/WebKitGTK/webkit-2.32/Source/WebCore/dom/SlotAssignment.cpp

    r282498 r282505  
    125125        assignSlots(shadowRoot);
    126126
     127    shadowRoot.host()->setHasShadowRootContainingSlots(true);
     128    m_slotElementCount++;
     129
    127130    bool needsSlotchangeEvent = shadowRoot.shouldFireSlotchangeEvent() && hasAssignedNodes(shadowRoot, slot);
    128131
     
    152155#endif
    153156
    154     if (auto* host = shadowRoot.host()) // FIXME: We should be able to do a targeted reconstruction.
     157    ASSERT(m_slotElementCount > 0);
     158    m_slotElementCount--;
     159
     160    if (auto host = makeRefPtr(shadowRoot.host())) {
     161        // FIXME: We should be able to do a targeted reconstruction.
    155162        host->invalidateStyleAndRenderersForSubtree();
     163        if (!m_slotElementCount)
     164            host->setHasShadowRootContainingSlots(false);
     165    }
    156166
    157167    auto* slot = m_slots.get(slotNameFromAttributeValue(name));
     
    338348}
    339349
     350void SlotAssignment::willRemoveAssignedNode(const Node& node)
     351{
     352    if (!m_slotAssignmentsIsValid)
     353        return;
     354
     355    if (!is<Text>(node) && !is<Element>(node))
     356        return;
     357
     358    auto* slot = m_slots.get(slotNameForHostChild(node));
     359    if (!slot || slot->assignedNodes.isEmpty())
     360        return;
     361
     362    slot->assignedNodes.removeFirstMatching([&node](const auto& item) {
     363        return item.get() == &node;
     364    });
     365}
     366
    340367const AtomString& SlotAssignment::slotNameForHostChild(const Node& child) const
    341368{
  • releases/WebKitGTK/webkit-2.32/Source/WebCore/dom/SlotAssignment.h

    r282498 r282505  
    6161
    6262    const Vector<WeakPtr<Node>>* assignedNodesForSlot(const HTMLSlotElement&, ShadowRoot&);
     63    void willRemoveAssignedNode(const Node&);
    6364
    6465    virtual void hostChildElementDidChange(const Element&, ShadowRoot&);
     
    104105    unsigned m_slotMutationVersion { 0 };
    105106    unsigned m_slotResolutionVersion { 0 };
     107    unsigned m_slotElementCount { 0 };
    106108};
    107109
     
    145147}
    146148
     149inline void ShadowRoot::willRemoveAssignedNode(const Node& node)
     150{
     151    if (m_slotAssignment)
     152        m_slotAssignment->willRemoveAssignedNode(node);
     153}
     154
    147155} // namespace WebCore
Note: See TracChangeset for help on using the changeset viewer.