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

MXRoomState/MXRoomMembers: Fix memory leak and copying #1040

Merged
merged 1 commit into from
Mar 16, 2021

Conversation

Johennes
Copy link
Contributor

@Johennes Johennes commented Mar 7, 2021

MXRoomState and MXRoomMembers currently hold mutual strong references to each other via the members property and the state ivar, respectively. This leads to a memory leak preventing both objects from being deallocated. The leak is easy to reproduce in the Element iOS app. Just launch the app, use a few rooms and start the memory graph debugger. At this point you'll find orphaned objects retaining each other such as:

Screenshot 2021-03-06 at 20 21 28

Additionally, the leak is masqueraded by a bug in MXRoomState's copyWithZone: method. The latter copies the MXRoomMembers object but doesn't update its state ivar to point to the MXRoomState copy. As a result, copying an MXRoomState object does not introduce another leak. I've noticed this when writing a unit test for the leak. Instead of the retain cycle, there now is a chain where MXRoomMembers is owned by one room state but points "back" to another.

Screenshot 2021-03-07 at 19 51 58

The present pull request addresses both issues. First, the state ivar on MXRoomMembers is made weak. This seems safe because MXRoomState retains its members property and MXRoomMembers should not exist on its own without a room state owning it.

Secondly, a new method copyWithZone:andState: is introduced on MXRoomMembers. The latter copies the receiver and updates the state ivar to the specified MXRoomState.

Pull Request Checklist

  • Pull request is based on the develop branch
  • Pull request updates CHANGES.rst
  • Pull request includes a sign off

`MXRoomState` and `MXRoomMembers` held mutual strong references to each other via
the `members` property and the `state` ivar, respectively. This led to a memory leak
preventing both objects from being deallocated.

Additionally, the leak was masqueraded by a bug in `MXRoomState`'s `copyWithZone:`
method. The latter copied the `MXRoomMembers` object but didn't update its `state`
ivar to point to the `MXRoomState` copy. As a result, copying an `MXRoomState` object
did *not* introduce another leak.

The present commit addresses both issues. First, the `state` ivar on `MXRoomMembers`
is made weak. This seems safe because `MXRoomState` retains its `members` property
and `MXRoomMembers` should not exist on its own without a room state owning it.

Secondly, a new method `copyWithZone:andState:` is introduced on `MXRoomMembers`. The
latter copies the receiver and updates the `state` ivar to the specified `MXRoomState`.

Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
@manuroe
Copy link
Contributor

manuroe commented Mar 16, 2021

Thanks @Johennes !

@manuroe manuroe merged commit 8e6fbb6 into matrix-org:develop Mar 16, 2021
manuroe added a commit that referenced this pull request Apr 14, 2021
element-hq/element-ios/issues/4204

Fix a regression introduced by #1040.
While paginating, the kept MXRoomState instance could be released, creating a bad view of room members. 

Remove the bad dependency to MXRoomState to avoid any retain cycle.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants