Title: [289355] trunk/Source/WebCore
Revision
289355
Author
[email protected]
Date
2022-02-07 19:31:51 -0800 (Mon, 07 Feb 2022)

Log Message

Prevent removal of isolated objects from a different parent than the current parent.
https://bugs.webkit.org/show_bug.cgi?id=236250
<rdar://problem/88585928>

Reviewed by Chris Fleizach.

AXObjectCache::remove may be called for an object after that object has
been re-parented. In those cases, we don't want to remove the corresponding
isolated object from its new location in the tree.
In addition, AXIsolatedTree:removeSubtreeFromNodeMap now properly updates
the children IDs for the parent of the object being removed.

* accessibility/AXObjectCache.cpp:
(WebCore::AXObjectCache::remove):
* accessibility/isolatedtree/AXIsolatedTree.cpp:
(WebCore::AXIsolatedTree::nodeChangeForObject):
(WebCore::AXIsolatedTree::queueChange):
(WebCore::AXIsolatedTree::collectNodeChangesForSubtree):
(WebCore::AXIsolatedTree::nodeAncestryChanges):
(WebCore::AXIsolatedTree::updateChildren):
(WebCore::AXIsolatedTree::removeNode):
(WebCore::AXIsolatedTree::removeSubtreeFromNodeMap):
* accessibility/isolatedtree/AXIsolatedTree.h:
(WebCore::AXIsolatedTree::removeSubtreeFromNodeMap):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (289354 => 289355)


--- trunk/Source/WebCore/ChangeLog	2022-02-08 03:00:28 UTC (rev 289354)
+++ trunk/Source/WebCore/ChangeLog	2022-02-08 03:31:51 UTC (rev 289355)
@@ -1,3 +1,30 @@
+2022-02-07  Andres Gonzalez  <[email protected]>
+
+        Prevent removal of isolated objects from a different parent than the current parent.
+        https://bugs.webkit.org/show_bug.cgi?id=236250
+        <rdar://problem/88585928>
+
+        Reviewed by Chris Fleizach.
+
+        AXObjectCache::remove may be called for an object after that object has
+        been re-parented. In those cases, we don't want to remove the corresponding
+        isolated object from its new location in the tree.
+        In addition, AXIsolatedTree:removeSubtreeFromNodeMap now properly updates
+        the children IDs for the parent of the object being removed.
+
+        * accessibility/AXObjectCache.cpp:
+        (WebCore::AXObjectCache::remove):
+        * accessibility/isolatedtree/AXIsolatedTree.cpp:
+        (WebCore::AXIsolatedTree::nodeChangeForObject):
+        (WebCore::AXIsolatedTree::queueChange):
+        (WebCore::AXIsolatedTree::collectNodeChangesForSubtree):
+        (WebCore::AXIsolatedTree::nodeAncestryChanges):
+        (WebCore::AXIsolatedTree::updateChildren):
+        (WebCore::AXIsolatedTree::removeNode):
+        (WebCore::AXIsolatedTree::removeSubtreeFromNodeMap):
+        * accessibility/isolatedtree/AXIsolatedTree.h:
+        (WebCore::AXIsolatedTree::removeSubtreeFromNodeMap):
+
 2022-02-07  Brent Fulgham  <[email protected]>
 
         Always sync ResourceRequest isAppInitiated request with NSURLRequest attribution value

Modified: trunk/Source/WebCore/accessibility/AXObjectCache.cpp (289354 => 289355)


--- trunk/Source/WebCore/accessibility/AXObjectCache.cpp	2022-02-08 03:00:28 UTC (rev 289354)
+++ trunk/Source/WebCore/accessibility/AXObjectCache.cpp	2022-02-08 03:31:51 UTC (rev 289355)
@@ -841,17 +841,17 @@
     if (!axID)
         return;
 
+    auto object = m_objects.take(axID);
+    if (!object)
+        return;
+
 #if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
     if (m_pageID) {
         if (auto tree = AXIsolatedTree::treeForPageID(*m_pageID))
-            tree->removeNode(axID);
+            tree->removeNode(*object);
     }
 #endif
 
-    auto object = m_objects.take(axID);
-    if (!object)
-        return;
-
     object->detach(AccessibilityDetachmentType::ElementDestroyed);
 
     m_idsInUse.remove(axID);

Modified: trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.cpp (289354 => 289355)


--- trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.cpp	2022-02-08 03:00:28 UTC (rev 289354)
+++ trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.cpp	2022-02-08 03:31:51 UTC (rev 289355)
@@ -232,7 +232,7 @@
     }
 
     if (updateNodeMap)
-        m_nodeMap.set(axObject.objectID(), axObject.childrenIDs());
+        m_nodeMap.set(axObject.objectID(), ParentChildrenIDs { parentID, axObject.childrenIDs() });
 
     if (!parentID.isValid()) {
         Locker locker { m_changeLogLock };
@@ -252,7 +252,7 @@
     AXID parentID = nodeChange.isolatedObject->parent();
     if (parentID.isValid()) {
         ASSERT_WITH_MESSAGE(m_nodeMap.contains(parentID), "node map should've contained parentID: %s", parentID.loggingString().utf8().data());
-        auto siblingsIDs = m_nodeMap.get(parentID);
+        auto siblingsIDs = m_nodeMap.get(parentID).childrenIDs;
         m_pendingChildrenUpdates.append({ parentID, WTFMove(siblingsIDs) });
     }
 
@@ -259,7 +259,7 @@
     AXID objectID = nodeChange.isolatedObject->objectID();
     ASSERT_WITH_MESSAGE(objectID != parentID, "object ID was the same as its parent ID (%s) when queueing a node change", objectID.loggingString().utf8().data());
     ASSERT_WITH_MESSAGE(m_nodeMap.contains(objectID), "node map should've contained objectID: %s", objectID.loggingString().utf8().data());
-    auto childrenIDs = m_nodeMap.get(objectID);
+    auto childrenIDs = m_nodeMap.get(objectID).childrenIDs;
     m_pendingChildrenUpdates.append({ objectID, WTFMove(childrenIDs) });
 }
 
@@ -298,7 +298,7 @@
         axChildrenIDs.uncheckedAppend(axChild->objectID());
     }
 
-    m_nodeMap.set(axObject.objectID(), axChildrenIDs);
+    m_nodeMap.set(axObject.objectID(), ParentChildrenIDs { parentID, axChildrenIDs });
 }
 
 void AXIsolatedTree::updateNode(AXCoreObject& axObject)
@@ -369,8 +369,11 @@
         idsBeingChanged.add(change.isolatedObject->objectID());
         changes.append(WTFMove(change));
 
-        if (axParent)
-            m_nodeMap.set(axParent->objectID(), axParent->childrenIDs());
+        if (axParent && m_nodeMap.contains(axParent->objectID())) {
+            auto ids = m_nodeMap.get(axParent->objectID());
+            ids.childrenIDs = axParent->childrenIDs();
+            m_nodeMap.set(axParent->objectID(), WTFMove(ids));
+        }
 
         axObject = axParent;
     }
@@ -403,7 +406,8 @@
     // isolated object to the closest existing ancestor.
     Vector<NodeChange> changes = nodeAncestryChanges(axObject, idsBeingChanged);
 
-    auto oldChildrenIDs = m_nodeMap.get(axObject.objectID());
+    auto oldIDs = m_nodeMap.get(axObject.objectID());
+    auto& oldChildrenIDs = oldIDs.childrenIDs;
 
     const auto& newChildren = axObject.children();
     auto newChildrenIDs = axObject.childrenIDs(false);
@@ -421,7 +425,7 @@
             collectNodeChangesForSubtree(*newChildren[i], axObject.objectID(), true, changes, &idsBeingChanged);
         }
     }
-    m_nodeMap.set(axObject.objectID(), newChildrenIDs);
+    m_nodeMap.set(axObject.objectID(), ParentChildrenIDs { oldIDs.parentID, newChildrenIDs });
 
     // What is left in oldChildrenIDs are the IDs that are no longer children of axObject.
     // Thus, remove them from m_nodeMap and queue them to be removed from the tree.
@@ -431,7 +435,7 @@
         //   1. Object 123 is slated to be a child of this object (i.e. in newChildren), and we collect node changes for it.
         //   2. Object 123 is currently a member of a subtree of some other object in oldChildrenIDs.
         //   3. Thus, we don't want to delete Object 123 from the nodemap, instead allowing it to be moved.
-        removeSubtreeFromNodeMap(axID, idsBeingChanged);
+        removeSubtreeFromNodeMap(axID, &axObject, idsBeingChanged);
     }
     queueChangesAndRemovals(changes, oldChildrenIDs);
 }
@@ -490,24 +494,34 @@
     m_pendingLoadingProgress = newProgressValue;
 }
 
-void AXIsolatedTree::removeNode(AXID axID)
+void AXIsolatedTree::removeNode(const AXCoreObject& axObject)
 {
     AXTRACE("AXIsolatedTree::removeNode");
-    AXLOG(makeString("AXID ", axID.loggingString()));
+    AXLOG(makeString("objectID ", axObject.objectID().loggingString()));
     ASSERT(isMainThread());
 
-    m_nodeMap.remove(axID);
-    Locker locker { m_changeLogLock };
-    m_pendingNodeRemovals.append(axID);
+    removeSubtreeFromNodeMap(axObject.objectID(), axObject.parentObjectUnignored());
+    queueChangesAndRemovals({ }, { axObject.objectID() });
 }
 
-void AXIsolatedTree::removeSubtreeFromNodeMap(AXID axID, const HashSet<AXID>& idsToKeep)
+void AXIsolatedTree::removeSubtreeFromNodeMap(AXID objectID, AXCoreObject* axParent, const HashSet<AXID>& idsToKeep)
 {
-    AXTRACE("AXIsolatedTree::removeSubtree");
-    AXLOG(makeString("Removing subtree for axID ", axID.loggingString()));
+    AXTRACE("AXIsolatedTree::removeSubtreeFromNodeMap");
+    AXLOG(makeString("Removing subtree for objectID ", objectID.loggingString()));
     ASSERT(isMainThread());
 
-    Vector<AXID> removals = { axID };
+    if (!m_nodeMap.contains(objectID)) {
+        AXLOG("Tried to remove AXID that is no longer in m_nodeMap.");
+        return;
+    }
+
+    AXID axParentID = axParent ? axParent->objectID() : AXID();
+    if (axParentID != m_nodeMap.get(objectID).parentID) {
+        AXLOG(makeString("Tried to remove object from a different parent ", axParentID.loggingString(), ", actual parent ", m_nodeMap.get(objectID).parentID.loggingString(), ", bailing out."));
+        return;
+    }
+
+    Vector<AXID> removals = { objectID };
     while (removals.size()) {
         AXID axID = removals.takeLast();
         if (!axID.isValid() || idsToKeep.contains(axID))
@@ -515,10 +529,17 @@
 
         auto it = m_nodeMap.find(axID);
         if (it != m_nodeMap.end()) {
-            removals.appendVector(it->value);
+            removals.appendVector(it->value.childrenIDs);
             m_nodeMap.remove(axID);
         }
     }
+
+    // Update the childrenIDs of the parent since one of its children has been removed.
+    if (axParent) {
+        auto ids = m_nodeMap.get(axParentID);
+        ids.childrenIDs = axParent->childrenIDs();
+        m_nodeMap.set(axParentID, WTFMove(ids));
+    }
 }
 
 void AXIsolatedTree::applyPendingChanges()

Modified: trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.h (289354 => 289355)


--- trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.h	2022-02-08 03:00:28 UTC (rev 289354)
+++ trunk/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.h	2022-02-08 03:31:51 UTC (rev 289355)
@@ -359,10 +359,10 @@
     double loadingProgress() { return m_loadingProgress; }
     void updateLoadingProgress(double);
 
-    // Removes the given node leaving all descendants alone.
-    void removeNode(AXID);
-    // Removes the given node and all its descendants.
-    void removeSubtreeFromNodeMap(AXID, const HashSet<AXID>& = { });
+    // Removes the corresponding isolated object and all descendants from the m_nodeMap and queues their removal from the tree.
+    void removeNode(const AXCoreObject&);
+    // Removes the given node and all its descendants from m_nodeMap.
+    void removeSubtreeFromNodeMap(AXID axID, AXCoreObject*, const HashSet<AXID>& = { });
 
     // Both setRootNodeID and setFocusedNodeID are called during the generation
     // of the IsolatedTree.
@@ -397,8 +397,17 @@
     AXObjectCache* m_axObjectCache { nullptr };
     bool m_usedOnAXThread { true };
 
-    // Only accessed on main thread.
-    HashMap<AXID, Vector<AXID>> m_nodeMap;
+    // Stores the parent ID and children IDS for a given IsolatedObject.
+    struct ParentChildrenIDs {
+        AXID parentID;
+        Vector<AXID> childrenIDs;
+    };
+    // Only accessed on the main thread.
+    // A representation of the tree's parent-child relationships. Each
+    // IsolatedObject must have one and only one entry in this map, that maps
+    // its ObjectID to its ParentChildrenIDs struct.
+    HashMap<AXID, ParentChildrenIDs> m_nodeMap;
+
     // Only accessed on AX thread requesting data.
     HashMap<AXID, Ref<AXIsolatedObject>> m_readerThreadNodeMap;
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to