Bug 237104 - Fix for AXIsolatedTree::updateChildren in the case when is called for a non-existing isolated object.
Summary: Fix for AXIsolatedTree::updateChildren in the case when is called for a non-e...
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: Accessibility (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Andres Gonzalez
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2022-02-23 12:50 PST by Andres Gonzalez
Modified: 2022-02-28 15:49 PST (History)
11 users (show)

See Also:


Attachments
Patch (3.84 KB, patch)
2022-02-23 13:02 PST, Andres Gonzalez
no flags Details | Formatted Diff | Diff
Patch (8.62 KB, patch)
2022-02-26 11:36 PST, Andres Gonzalez
no flags Details | Formatted Diff | Diff
Patch (8.24 KB, patch)
2022-02-27 06:48 PST, Andres Gonzalez
no flags Details | Formatted Diff | Diff
Patch (8.80 KB, patch)
2022-02-28 14:02 PST, Andres Gonzalez
ews-feeder: commit-queue-
Details | Formatted Diff | Diff
Patch (8.77 KB, patch)
2022-02-28 15:12 PST, Andres Gonzalez
andresg_22: review?
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Andres Gonzalez 2022-02-23 12:50:03 PST
AXIsolatedTree::updateChildren should update the entire subtree if there are no differences in the children of the existing isolated object.
Comment 1 Radar WebKit Bug Importer 2022-02-23 12:50:17 PST
<rdar://problem/89372850>
Comment 2 Andres Gonzalez 2022-02-23 13:02:58 PST
Created attachment 453015 [details]
Patch
Comment 3 Andres Gonzalez 2022-02-26 11:36:28 PST
Created attachment 453303 [details]
Patch
Comment 4 Darin Adler 2022-02-26 14:36:20 PST
Comment on attachment 453303 [details]
Patch

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

review- because of the move semantic mistake

> Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.cpp:293
> +    axChildrenIDs.reserveInitialCapacity(axChildrenCopy.size());

If it’s going to be common to return a vector much smaller than this, we may want to use shrinkToFit. On the other hand, if it’s a temporary that’s immediately used and deallocated then not so important.

> Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.cpp:295
> +        collectNodeChangesForSubtree(*axChild, axObject.objectID(), attachWrapper, changes, idsBeingChanged, WTFMove(filter));

This isn’t safe. We can’t use the function after moving it. I suggest passing the Function as const&, not &&.

In some parts of our code, we figure out ways do to this kind of thing without recursion.
Comment 5 Darin Adler 2022-02-26 14:38:48 PST
Comment on attachment 453303 [details]
Patch

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

>> Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.cpp:295
>> +        collectNodeChangesForSubtree(*axChild, axObject.objectID(), attachWrapper, changes, idsBeingChanged, WTFMove(filter));
> 
> This isn’t safe. We can’t use the function after moving it. I suggest passing the Function as const&, not &&.
> 
> In some parts of our code, we figure out ways do to this kind of thing without recursion.

My language here was imprecise:

We can’t use the function again after moving *from* it, so the next line of code where we call filter is a programming mistake. Best fix is probably to change this to take const Function<bool(const AXCoreObject)>& instead, and removing the WTFMove.
Comment 6 Andres Gonzalez 2022-02-27 06:48:46 PST
Created attachment 453340 [details]
Patch
Comment 7 Andres Gonzalez 2022-02-27 07:00:55 PST
(In reply to Darin Adler from comment #5)
> Comment on attachment 453303 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=453303&action=review
> 
> >> Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.cpp:295
> >> +        collectNodeChangesForSubtree(*axChild, axObject.objectID(), attachWrapper, changes, idsBeingChanged, WTFMove(filter));
> > 
> > This isn’t safe. We can’t use the function after moving it. I suggest passing the Function as const&, not &&.
> > 
> > In some parts of our code, we figure out ways do to this kind of thing without recursion.
> 
> My language here was imprecise:
> 
> We can’t use the function again after moving *from* it, so the next line of
> code where we call filter is a programming mistake. Best fix is probably to
> change this to take const Function<bool(const AXCoreObject)>& instead, and
> removing the WTFMove.

Fixed both issues that you pointed out. Concerning the move of a Function, thought that use after move would be ok in this case because the only state that Function is probably keeping is the address of the lambda, and that should be valid after the move, assuming that the move is not zeroing out that address. I.e., for Function, move and copy are the same. But I may be missing something about the implementation of Function. Also agree that for consistency with the move semantics, shouldn't be used after move. Thanks!
Comment 8 Darin Adler 2022-02-27 07:49:12 PST
(In reply to Andres Gonzalez from comment #7)
> Fixed both issues that you pointed out. Concerning the move of a Function,
> thought that use after move would be ok in this case because the only state
> that Function is probably keeping is the address of the lambda, and that
> should be valid after the move, assuming that the move is not zeroing out
> that address. I.e., for Function, move and copy are the same. But I may be
> missing something about the implementation of Function. Also agree that for
> consistency with the move semantics, shouldn't be used after move. Thanks!

Yes, I can’t emphasize this enough:

it would be *very* dangerous to use after move because we designed a particular class to be usable after moving; makes little sense but is of course possible to make a class work this way. We should absolutely *not* rely on WTF::Function being designed for use after moving from, even if it happens to be true due to implementation details at time of this writing.

In fact, we should probably go the other direction and create debug assertions for classes we design to catch use-after-move mistakes.
Comment 9 Andres Gonzalez 2022-02-28 14:02:17 PST
Created attachment 453424 [details]
Patch
Comment 10 Darin Adler 2022-02-28 14:09:59 PST
Comment on attachment 453424 [details]
Patch

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

> Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.cpp:437
> +    auto isAncestor = Function<FilterResponse(const AXCoreObject&)>([&axDescendant] (const AXCoreObject& axAncestor) {

I’d think we’d want this local to just be the lambda and construct the function as a side effect of passing it to collectNodeChangesForSubtree. Did you try that?

> Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.h:398
> +    enum class FilterResponse : uint8_t {
> +        Include,
> +        Skip,
> +        Stop,
> +    };

I think these read better as one-liners.
Comment 11 Andres Gonzalez 2022-02-28 15:12:00 PST
Created attachment 453439 [details]
Patch
Comment 12 Andres Gonzalez 2022-02-28 15:25:38 PST
(In reply to Darin Adler from comment #10)
> Comment on attachment 453424 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=453424&action=review
> 
> > Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.cpp:437
> > +    auto isAncestor = Function<FilterResponse(const AXCoreObject&)>([&axDescendant] (const AXCoreObject& axAncestor) {
> 
> I’d think we’d want this local to just be the lambda and construct the
> function as a side effect of passing it to collectNodeChangesForSubtree. Did
> you try that?

Tried several variants with no luck, except this one. Either get

error: no viable conversion from '(lambda at ./accessibility/isolatedtree/AXIsolatedTree.cpp:437:23)' to 'const Function<WebCore::AXIsolatedTree::FilterResponse (const WebCore::AXCoreObject &)>'

or

error: no matching constructor for initialization of 'const Function<WebCore::AXIsolatedTree::FilterResponse (const WebCore::AXCoreObject &)> &'

> 
> > Source/WebCore/accessibility/isolatedtree/AXIsolatedTree.h:398
> > +    enum class FilterResponse : uint8_t {
> > +        Include,
> > +        Skip,
> > +        Stop,
> > +    };
> 
> I think these read better as one-liners.

Yes, done. Thanks.