Bug 241650

Summary: AX: AccessibilityObject::insertChild does not check the validity of the insertionIndex while processing grandchildren
Product: WebKit Reporter: Tyler Wilcock <tyler_w>
Component: AccessibilityAssignee: Tyler Wilcock <tyler_w>
Status: RESOLVED FIXED    
Severity: Normal CC: aboxhall, andresg_22, apinheiro, cfleizach, dmazzoni, ews-watchlist, jcraig, jdiggs, samuel_white, webkit-bug-importer
Priority: P2 Keywords: InRadar
Version: WebKit Nightly Build   
Hardware: Unspecified   
OS: Unspecified   
Attachments:
Description Flags
Patch none

Description Tyler Wilcock 2022-06-15 14:47:35 PDT
This can cause crashes.
Comment 1 Radar WebKit Bug Importer 2022-06-15 14:47:42 PDT
<rdar://problem/95240529>
Comment 2 Tyler Wilcock 2022-06-15 15:03:03 PDT
Created attachment 460262 [details]
Patch
Comment 3 Tyler Wilcock 2022-06-15 16:27:10 PDT
rdar://94895437
Comment 4 chris fleizach 2022-06-15 17:48:12 PDT
Comment on attachment 460262 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=460262&action=review

> Source/WebCore/accessibility/AccessibilityObject.cpp:636
> +                    if (insertionIndex > m_children.size())

do we want to insert this at position 0 in this case? or discard completely?
Comment 5 Tyler Wilcock 2022-06-15 18:52:39 PDT
(In reply to chris fleizach from comment #4)
> Comment on attachment 460262 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=460262&action=review
> 
> > Source/WebCore/accessibility/AccessibilityObject.cpp:636
> > +                    if (insertionIndex > m_children.size())
> 
> do we want to insert this at position 0 in this case? or discard completely?
I think we want to discard this grandchild (and any following) entirely, since they may no longer be the right children after the layout that caused m_children to be cleared.

Also, when this happens, m_childrenInitialized should always become false (it does in the crash I was chasing down), meaning we will add the actually-correct children in the next call to children(true).
Comment 6 Andres Gonzalez 2022-06-16 07:57:33 PDT
(In reply to Tyler Wilcock from comment #2)
> Created attachment 460262 [details]
> Patch

It seems that what we are doing in this whole block is to insert the grandchildren if the newChild is ignored. Would it make it clearer if add a method called insertchildren(const Vector&, size_t index), and then we could write in the body of this block: 
    if (descendIfIgnored == DescendIfIgnored::Yes
        && child->accessibilityIsIgnored()) 
        insertChildren(child->children(), index);
Comment 7 Tyler Wilcock 2022-06-16 10:51:58 PDT
(In reply to Andres Gonzalez from comment #6)
> (In reply to Tyler Wilcock from comment #2)
> > Created attachment 460262 [details]
> > Patch
> 
> It seems that what we are doing in this whole block is to insert the
> grandchildren if the newChild is ignored. Would it make it clearer if add a
> method called insertchildren(const Vector&, size_t index), and then we could
> write in the body of this block: 
>     if (descendIfIgnored == DescendIfIgnored::Yes
>         && child->accessibilityIsIgnored()) 
>         insertChildren(child->children(), index);
I tried this out and unfortunately we'd also need to pass a third AXAncestorFlags parameter (to capture the flags of the ignored object), which IMO makes this refactor not worth it.
Comment 8 Andres Gonzalez 2022-06-16 12:31:09 PDT
(In reply to Tyler Wilcock from comment #7)
> (In reply to Andres Gonzalez from comment #6)
> > (In reply to Tyler Wilcock from comment #2)
> > > Created attachment 460262 [details]
> > > Patch
> > 
> > It seems that what we are doing in this whole block is to insert the
> > grandchildren if the newChild is ignored. Would it make it clearer if add a
> > method called insertchildren(const Vector&, size_t index), and then we could
> > write in the body of this block: 
> >     if (descendIfIgnored == DescendIfIgnored::Yes
> >         && child->accessibilityIsIgnored()) 
> >         insertChildren(child->children(), index);
> I tried this out and unfortunately we'd also need to pass a third
> AXAncestorFlags parameter (to capture the flags of the ignored object),
> which IMO makes this refactor not worth it.

No, you can do

    auto ancestorFlags = computeAncestorFlags();

inside insertObjects(...), no need to pass it as a param. Changed the name from insertchildren to insertObjects because in this case you would be inserting the grandChildren. I believe it would make the code maintainable.
Comment 9 Andres Gonzalez 2022-06-16 12:40:36 PDT
(In reply to Andres Gonzalez from comment #8)
> (In reply to Tyler Wilcock from comment #7)
> > (In reply to Andres Gonzalez from comment #6)
> > > (In reply to Tyler Wilcock from comment #2)
> > > > Created attachment 460262 [details]
> > > > Patch
> > > 
> > > It seems that what we are doing in this whole block is to insert the
> > > grandchildren if the newChild is ignored. Would it make it clearer if add a
> > > method called insertchildren(const Vector&, size_t index), and then we could
> > > write in the body of this block: 
> > >     if (descendIfIgnored == DescendIfIgnored::Yes
> > >         && child->accessibilityIsIgnored()) 
> > >         insertChildren(child->children(), index);
> > I tried this out and unfortunately we'd also need to pass a third
> > AXAncestorFlags parameter (to capture the flags of the ignored object),
> > which IMO makes this refactor not worth it.
> 
> No, you can do
> 
>     auto ancestorFlags = computeAncestorFlags();
> 
> inside insertObjects(...), no need to pass it as a param. Changed the name
> from insertchildren to insertObjects because in this case you would be
> inserting the grandChildren. I believe it would make the code maintainable.

The name insertChildren is fine, thought for a moment that insertObjects was better but it is not, since you are inserting children that in this case happen to be grandchildren.
Comment 10 Tyler Wilcock 2022-06-16 16:44:22 PDT
(In reply to Andres Gonzalez from comment #8)
> (In reply to Tyler Wilcock from comment #7)
> > (In reply to Andres Gonzalez from comment #6)
> > > (In reply to Tyler Wilcock from comment #2)
> > > > Created attachment 460262 [details]
> > > > Patch
> > > 
> > > It seems that what we are doing in this whole block is to insert the
> > > grandchildren if the newChild is ignored. Would it make it clearer if add a
> > > method called insertchildren(const Vector&, size_t index), and then we could
> > > write in the body of this block: 
> > >     if (descendIfIgnored == DescendIfIgnored::Yes
> > >         && child->accessibilityIsIgnored()) 
> > >         insertChildren(child->children(), index);
> > I tried this out and unfortunately we'd also need to pass a third
> > AXAncestorFlags parameter (to capture the flags of the ignored object),
> > which IMO makes this refactor not worth it.
> 
> No, you can do
> 
>     auto ancestorFlags = computeAncestorFlags();
> 
> inside insertObjects(...), no need to pass it as a param. Changed the name
> from insertchildren to insertObjects because in this case you would be
> inserting the grandChildren. I believe it would make the code maintainable.
The current behavior is to use the ancestor flags of the ignored child rather than `this` as you suggest. Using `this` ancestor flags might be OK...but I don't want to make that behavior change in this patch. Let's address this refactor in a separate patch.
Comment 11 EWS 2022-06-16 17:21:16 PDT
Committed r295618 (251623@main): <https://commits.webkit.org/251623@main>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 460262 [details].