Index: ui/accessibility/ax_tree.cc |
diff --git a/ui/accessibility/ax_tree.cc b/ui/accessibility/ax_tree.cc |
index d07f239b79d9a292b1221239067b71ee2b715e03..c2fb44dd5625ddc2a23fc85b84a8b33d9cde548b 100644 |
--- a/ui/accessibility/ax_tree.cc |
+++ b/ui/accessibility/ax_tree.cc |
@@ -89,8 +89,11 @@ bool AXTree::Unserialize(const AXTreeUpdate& update) { |
return false; |
} |
if (node == root_) { |
- DestroySubtree(root_, &update_state); |
- root_ = NULL; |
+ // Clear root_ before calling DestroySubtree so that root_ doesn't |
+ // ever point to an invalid node. |
+ AXNode* old_root = root_; |
+ root_ = nullptr; |
+ DestroySubtree(old_root, &update_state); |
} else { |
for (int i = 0; i < node->child_count(); ++i) |
DestroySubtree(node->ChildAtIndex(i), &update_state); |
@@ -204,9 +207,12 @@ bool AXTree::UpdateNode(const AXNodeData& src, |
// Update the root of the tree if needed. |
if ((src.role == AX_ROLE_ROOT_WEB_AREA || src.role == AX_ROLE_DESKTOP) && |
(!root_ || root_->id() != src.id)) { |
- if (root_) |
- DestroySubtree(root_, update_state); |
+ // Make sure root_ always points to something valid or null_, even inside |
+ // DestroySubtree. |
+ AXNode* old_root = root_; |
root_ = node; |
+ if (old_root) |
+ DestroySubtree(old_root, update_state); |
} |
return success; |
@@ -221,11 +227,11 @@ void AXTree::DestroySubtree(AXNode* node, |
void AXTree::DestroyNodeAndSubtree(AXNode* node, |
AXTreeUpdateState* update_state) { |
+ if (delegate_) |
+ delegate_->OnNodeWillBeDeleted(this, node); |
id_map_.erase(node->id()); |
for (int i = 0; i < node->child_count(); ++i) |
DestroyNodeAndSubtree(node->ChildAtIndex(i), update_state); |
- if (delegate_) |
- delegate_->OnNodeWillBeDeleted(this, node); |
if (update_state) { |
update_state->pending_nodes.erase(node); |
} |