Fix retain cycles in AnnouncementsDataStoreTests and GutenbergVideoUploadProcessor#25548
Open
amanjeetsingh150 wants to merge 2 commits intowordpress-mobile:trunkfrom
Open
Conversation
Each of the four tests stores `subscription = store.onChange { … store.x … }`
in an instance property. The closure captures the local `store` strongly,
which is then retained by `CachedAnnouncementsStore.changeDispatcher`'s
observers dictionary, forming the cycle:
store → changeDispatcher → observers[token] → closure → store
Without a `tearDown`, the `Receipt` only deinits when XCTest tears down the
test instance, which it defers when more tests are queued in the class —
so the cycle is observable by the end-of-test leak snapshot.
Adding `tearDown` to nil out `subscription` triggers the `Receipt.deinit`
unsubscribe path immediately and breaks the cycle.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The three `lazy var` properties (`videoHtmlProcessor`, `videoBlockProcessor`,
`mediaTextVideoBlockProcessor`) each construct a child processor whose
`replacer:` closure references `self` without a capture list. The child
processor is owned strongly by `self`, and the closure retained inside it
captures `self` strongly — producing three independent 2-node cycles:
GutenbergVideoUploadProcessor
→ videoHtmlProcessor (HTMLProcessor)
→ replacer.context → captures self
→ GutenbergVideoUploadProcessor (cycle)
Switching each closure to `[weak self]` (with a `guard let self` early-out)
breaks the back-edge. By ownership, the closure is only invoked while
`self` is still alive, so the guard never trips in practice.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #25547.
Report:
wp-local-audit-Xcode26.0.zip
Description
Fixes two distinct retain cycles surfaced by XCTestLeaks against the
WordPressscheme.1.
AnnouncementsDataStoreTests(test code)The four tests stash
subscription = store.onChange { … store.x … }as an instance property; the closure captures the localstorestrongly and is retained byDispatcher.observers. Without atearDowntheReceiptonly deinits when XCTest tears the test instance down, which is deferred when the class has multiple queued tests — long enough for the post-test leak snapshot to observe the cycle.Fix: add
tearDownthat nilssubscription. TheReceipt'sdeinitthen callsunsubscribeimmediately, removing the closure fromobserversand breaking the cycle.2.
GutenbergVideoUploadProcessor(production code)Three
lazy varproperties construct child processors whosereplacer:closures referenceself.remoteURLString/self.mediaUploadIDwithout a capture list. Each lazy property is strongly owned byselfand retains a closure that capturesselfstrongly — three independent two-node cycles.Fix:
[weak self] + guard let selfin all three closures. By ownership the closure can only execute whileselfis alive, so the guard is never tripped in practice.Testing
Both reported
0 leakson this branch and the original leak counts ontrunk.Notes for reviewers
The first leak is in test file, I'm open to revert let me know how'd you feel about it. The second one is production leak and we can get that in.