Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Started clearing out the parent of orphaned semantic objects. #17499

Merged
merged 5 commits into from
Apr 3, 2020

Conversation

gaaclarke
Copy link
Member

@gaaclarke gaaclarke commented Apr 3, 2020

Relevant issue: flutter/flutter#53827

The actual bug was here: https://github.com/gaaclarke/engine/blob/3185a9fca1386f5ba062f7adafa4d102f2d7e036/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm#L759:L759.
We weren't clearing out the parent.

The following changes have been made to make the code more robust:

  1. SemanticsObject.parent is no longer settable publicly. Editing of that field now happens only in SemanticsObject in reaction to editing its children.
  2. SemanticsObject.children no longer returns a mutable collection. All edits must go through -[SemanticsObject setChildren:] or -[SemanticsObject replaceChildAtIndex:withChild:].

@gaaclarke gaaclarke marked this pull request as ready for review April 3, 2020 18:16
@auto-assign auto-assign bot requested a review from liyuqian April 3, 2020 18:16
}
[_children removeAllObjects];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was added previously to prevent a different memory leak. Are we sure we're not leaking a11y objects with this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is redundant, the next line deletes the whole collection which will release all of its items. If this appeared to fix something, there is a deeper problem somewhere else.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may have just been paranoia :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The most likely scenario is that if this fixed something, [_children release] is not actually deleting _children. I've audited it and the code looks fine. Maybe this was not the case in the past. This was the most likely culprit, but it correctly has an autorelease on it: https://github.com/gaaclarke/engine/blob/da3ffbf8562299dbfa5b4b2ab42c142b79a5b0af/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm#L770:L770

Copy link
Member Author

@gaaclarke gaaclarke Apr 3, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another possibility is that someone is holding onto the SemanticsObject.children, if they were doing that, I don't think we should be clearing it out. I'll put it back in since it doesn't have direct impact on the issue.

@@ -162,8 +164,14 @@ - (instancetype)initWithSemanticsObject:(SemanticsObject*)semanticsObject

@end

@interface SemanticsObject ()
/** Should only be called in conjunction with setting child/parent relationship. */
- (void)privateSetParent:(SemanticsObject*)parent;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see how this really helps us vs. having the parent property be writable. It's not like there were other TUs setting the property. Can you explain a bit?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the point is we want to control the editing of the parent property. We want to enforce that editing it happens in conjunction with editing children. If we were using another language I could make the setter private. Here i just do it by convention and naming. We could split SemanticsObject into its own file and make it truly private if you aren't happy with how it's setup.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't we just leave it as _parent = parent? Am I just forgetting how Objective C works?

Copy link
Member Author

@gaaclarke gaaclarke Apr 3, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because you are calling it on someone else:

void SemanticObject.addChild(SemanticObject child) {
  _children.append(child);
  child.parent = this;
}

We want only SemanticObject to have access to the setter, we don't want the accessibility bridge or whoever fiddling with it (private in a c++ sense). My hope was that when people see a method called "privateSetParent" they might think twice about who is suppose to be calling it and why.

to make sure an object isn't deleted beforehand
@gaaclarke gaaclarke requested a review from dnfield April 3, 2020 19:30
Copy link
Contributor

@dnfield dnfield left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Might be nice to expand the comment on privateSetParent to explain when it's valid to use it. We should just refactor this whole thing to make it more testable - one option might be a C++ tree impl that could be unit tested and then just used here.

@gaaclarke
Copy link
Member Author

@dnfield and I decided in chat to refactor SemanticsObject into its own class. I'll follow up with another PR.

@gaaclarke gaaclarke merged commit 4cfbe45 into flutter:master Apr 3, 2020
gaaclarke added a commit to gaaclarke/engine that referenced this pull request Apr 14, 2020
goderbauer pushed a commit to goderbauer/engine that referenced this pull request Apr 16, 2020
goderbauer pushed a commit to goderbauer/engine that referenced this pull request Apr 16, 2020
@magicleon94
Copy link

Has this reached the stable branch? We are experiencing this issue in our production app...

@gaaclarke
Copy link
Member Author

@magicleon94 You can find where commits are by looking at their roll commit into flutter/flutter: flutter/flutter@46ce54d

So, it looks like 1.18.0-6.0.pre and later have it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants