AX: Live AX objects can be destroyed while building a node change for them
https://bugs.webkit.org/show_bug.cgi?id=241810
Reviewed by Chris Fleizach.
While building a node change in AXIsolatedTree::nodeChangeForObject,
the initialization of several different `AXPropertyName`s can cause layout,
which in turn can cause the backing live object to be deleted. This
causes a crash.
This patch fixes this by holding a `Ref` to the AccessibilityObject,
ensuring it stays alive for as long we need it.
I wasn't able to make a layout test for this, as the circumstances to
reproduce the issue are complex.
* Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp:
(WebCore::AXIsolatedObject::AXIsolatedObject):
(WebCore::AXIsolatedObject::create):
(WebCore::AXIsolatedObject::initializeProperties):
* Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h:
* Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.cpp:
(WebCore::AXIsolatedTree::nodeChangeForObject):
* Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.h:
* Source/WebCore/accessibility/isolatedtree/mac/AXIsolatedObjectMac.mm:
(WebCore::AXIsolatedObject::initializePlatformProperties):
Canonical link: https://commits.webkit.org/251726@main
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@295721 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp b/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp
index 6f4b4fd..4dfd7c7 100644
--- a/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp
+++ b/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.cpp
@@ -38,18 +38,18 @@
namespace WebCore {
-AXIsolatedObject::AXIsolatedObject(AXCoreObject& axObject, AXIsolatedTree* tree)
+AXIsolatedObject::AXIsolatedObject(Ref<AXCoreObject> axObject, AXIsolatedTree* tree)
: m_cachedTree(tree)
- , m_id(axObject.objectID())
+ , m_id(axObject->objectID())
{
ASSERT(isMainThread());
ASSERT(is<AccessibilityObject>(axObject));
- auto* axParent = axObject.parentObjectUnignored();
+ auto* axParent = axObject->parentObjectUnignored();
m_parentID = axParent ? axParent->objectID() : AXID();
if (m_id.isValid()) {
- auto isRoot = !axParent && axObject.isScrollView() ? IsRoot::Yes : IsRoot::No;
+ auto isRoot = !axParent && axObject->isScrollView() ? IsRoot::Yes : IsRoot::No;
initializeProperties(axObject, isRoot);
} else {
// Should never happen under normal circumstances.
@@ -57,7 +57,7 @@
}
}
-Ref<AXIsolatedObject> AXIsolatedObject::create(AXCoreObject& object, AXIsolatedTree* tree)
+Ref<AXIsolatedObject> AXIsolatedObject::create(Ref<AXCoreObject> object, AXIsolatedTree* tree)
{
return adoptRef(*new AXIsolatedObject(object, tree));
}
@@ -72,10 +72,10 @@
ASSERT_NOT_REACHED();
}
-void AXIsolatedObject::initializeProperties(AXCoreObject& coreObject, IsRoot isRoot)
+void AXIsolatedObject::initializeProperties(Ref<AXCoreObject> coreObject, IsRoot isRoot)
{
ASSERT(is<AccessibilityObject>(coreObject));
- auto& object = downcast<AccessibilityObject>(coreObject);
+ auto& object = downcast<AccessibilityObject>(coreObject.get());
setProperty(AXPropertyName::ARIALandmarkRoleDescription, object.ariaLandmarkRoleDescription().isolatedCopy());
setProperty(AXPropertyName::AccessibilityDescription, object.accessibilityDescription().isolatedCopy());
@@ -400,7 +400,7 @@
if (object.isWidget())
setProperty(AXPropertyName::IsWidget, true);
- initializePlatformProperties(object, isRoot);
+ initializePlatformProperties(coreObject, isRoot);
}
AXCoreObject* AXIsolatedObject::associatedAXObject() const
diff --git a/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h b/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h
index 5abce8f..9513dc8 100644
--- a/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h
+++ b/Source/WebCore/accessibility/isolatedtree/AXIsolatedObject.h
@@ -47,7 +47,7 @@
class AXIsolatedObject final : public AXCoreObject {
friend class AXIsolatedTree;
public:
- static Ref<AXIsolatedObject> create(AXCoreObject&, AXIsolatedTree*);
+ static Ref<AXIsolatedObject> create(Ref<AXCoreObject>, AXIsolatedTree*);
~AXIsolatedObject();
void setObjectID(AXID id) override { m_id = id; }
@@ -66,13 +66,13 @@
AXIsolatedTree* tree() const { return m_cachedTree.get(); }
AXIsolatedObject() = default;
- AXIsolatedObject(AXCoreObject&, AXIsolatedTree*);
+ AXIsolatedObject(Ref<AXCoreObject>, AXIsolatedTree*);
bool isAXIsolatedObjectInstance() const override { return true; }
AXCoreObject* associatedAXObject() const;
enum class IsRoot : bool { Yes, No };
- void initializeProperties(AXCoreObject&, IsRoot);
- void initializePlatformProperties(const AXCoreObject&, IsRoot);
+ void initializeProperties(Ref<AXCoreObject>, IsRoot);
+ void initializePlatformProperties(Ref<const AXCoreObject>, IsRoot);
void setProperty(AXPropertyName, AXPropertyValueVariant&&, bool shouldRemove = false);
void setObjectProperty(AXPropertyName, AXCoreObject*);
diff --git a/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.cpp b/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.cpp
index 22662e9..bd83a98 100644
--- a/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.cpp
+++ b/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.cpp
@@ -209,15 +209,15 @@
queueRemovalsAndUnresolvedChanges({ });
}
-std::optional<AXIsolatedTree::NodeChange> AXIsolatedTree::nodeChangeForObject(AXCoreObject& axObject, AttachWrapper attachWrapper)
+std::optional<AXIsolatedTree::NodeChange> AXIsolatedTree::nodeChangeForObject(Ref<AXCoreObject> axObject, AttachWrapper attachWrapper)
{
ASSERT(isMainThread());
// We should never create an isolated object from an ignored object.
- if (axObject.accessibilityIsIgnored())
+ if (axObject->accessibilityIsIgnored())
return std::nullopt;
- if (!axObject.objectID().isValid()) {
+ if (!axObject->objectID().isValid()) {
// Either the axObject has an invalid ID or something else went terribly wrong. Don't bother doing anything else.
ASSERT_NOT_REACHED();
return std::nullopt;
@@ -226,15 +226,15 @@
auto object = AXIsolatedObject::create(axObject, this);
NodeChange nodeChange { object, nullptr };
- ASSERT(axObject.wrapper());
+ ASSERT(axObject->wrapper());
if (attachWrapper == AttachWrapper::OnMainThread)
- object->attachPlatformWrapper(axObject.wrapper());
+ object->attachPlatformWrapper(axObject->wrapper());
else {
// Set the wrapper in the NodeChange so that it is set on the AX thread.
- nodeChange.wrapper = axObject.wrapper();
+ nodeChange.wrapper = axObject->wrapper();
}
- m_nodeMap.set(axObject.objectID(), ParentChildrenIDs { nodeChange.isolatedObject->parent(), axObject.childrenIDs() });
+ m_nodeMap.set(axObject->objectID(), ParentChildrenIDs { nodeChange.isolatedObject->parent(), axObject->childrenIDs() });
if (!nodeChange.isolatedObject->parent().isValid()) {
Locker locker { m_changeLogLock };
diff --git a/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.h b/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.h
index 2497b52f..228e0e0 100644
--- a/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.h
+++ b/Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.h
@@ -385,7 +385,7 @@
static HashMap<PageIdentifier, Ref<AXIsolatedTree>>& treePageCache() WTF_REQUIRES_LOCK(s_cacheLock);
enum class AttachWrapper : bool { OnMainThread, OnAXThread };
- std::optional<NodeChange> nodeChangeForObject(AXCoreObject&, AttachWrapper = AttachWrapper::OnMainThread);
+ std::optional<NodeChange> nodeChangeForObject(Ref<AXCoreObject>, AttachWrapper = AttachWrapper::OnMainThread);
void collectNodeChangesForSubtree(AXCoreObject&);
bool isCollectingNodeChanges() const { return m_collectingNodeChangesAtTreeLevel > 0; }
void queueChange(const NodeChange&) WTF_REQUIRES_LOCK(m_changeLogLock);
diff --git a/Source/WebCore/accessibility/isolatedtree/mac/AXIsolatedObjectMac.mm b/Source/WebCore/accessibility/isolatedtree/mac/AXIsolatedObjectMac.mm
index ed19415..fdc26fe 100644
--- a/Source/WebCore/accessibility/isolatedtree/mac/AXIsolatedObjectMac.mm
+++ b/Source/WebCore/accessibility/isolatedtree/mac/AXIsolatedObjectMac.mm
@@ -32,18 +32,18 @@
namespace WebCore {
-void AXIsolatedObject::initializePlatformProperties(const AXCoreObject& object, IsRoot isRoot)
+void AXIsolatedObject::initializePlatformProperties(Ref<const AXCoreObject> object, IsRoot isRoot)
{
- setProperty(AXPropertyName::HasApplePDFAnnotationAttribute, object.hasApplePDFAnnotationAttribute());
- setProperty(AXPropertyName::SpeechHint, object.speechHintAttributeValue().isolatedCopy());
- setProperty(AXPropertyName::CaretBrowsingEnabled, object.caretBrowsingEnabled());
+ setProperty(AXPropertyName::HasApplePDFAnnotationAttribute, object->hasApplePDFAnnotationAttribute());
+ setProperty(AXPropertyName::SpeechHint, object->speechHintAttributeValue().isolatedCopy());
+ setProperty(AXPropertyName::CaretBrowsingEnabled, object->caretBrowsingEnabled());
if (isRoot == IsRoot::Yes)
- setProperty(AXPropertyName::PreventKeyboardDOMEventDispatch, object.preventKeyboardDOMEventDispatch());
+ setProperty(AXPropertyName::PreventKeyboardDOMEventDispatch, object->preventKeyboardDOMEventDispatch());
- if (object.isScrollView()) {
- m_platformWidget = object.platformWidget();
- m_remoteParent = object.remoteParentObject();
+ if (object->isScrollView()) {
+ m_platformWidget = object->platformWidget();
+ m_remoteParent = object->remoteParentObject();
}
}