firefox-ios
firefox-ios copied to clipboard
Memory leaks due to retain cycle between UI kit instances in SecondaryButton
Steps to reproduce
UI test to check for disabled suggestions. I wrote this with Maestro and dumped memory leaks at the end of the test through leaks cli. Leaks tools surfaced retain cycle from SecondaryRoundedButton which is common for the view controllers. Attaching the report below
- Launch app with command:
export SIMCTL_CHILD_MallocStackLogging=1 && xcrun simctl launch booted org.mozilla.ios.Fennec
to enable malloc logs and get process id from here. - Run the UI test with maestro test
./path/to/test.yaml
- Dump leaks with
leaks pid
.
Test:
appId: org.mozilla.ios.Fennec
---
- tapOn:
text: "Skip"
optional: true
- tapOn:
text: "Skip"
optional: true
- tapOn:
text: "Skip"
optional: true
- tapOn: "Search or enter address"
- inputText: "Wikipedia"
- assertNotVisible: "Empty list"
- tapOn:
id: "urlBar-cancel"
- tapOn:
id: "TabToolbar.menuButton"
- tapOn:
id: "settingsLarge"
- tapOn:
id: "Search"
- tapOn:
text: "1"
index: 0
- tapOn: "Settings"
- tapOn: "Done"
- tapOn: "Search or enter address"
- inputText: "Wikipedia"
- assertVisible: "Empty list"
There are total of 7 instances of this ROOT CYCLE: <UIKit>.
Example
STACK OF 1 INSTANCE OF 'ROOT CYCLE: <UIKit>':
50 dyld 0x1214003a6 start + 1942
49 dyld_sim 0x114602f21 start_sim + 10
48 org.mozilla.ios.Fennec 0x110849c96 main + 1014 main.swift:25
47 com.apple.UIKitCore 0x7fff250a32b5 UIApplicationMain + 101
46 com.apple.UIKitCore 0x7fff2509e65a -[UIApplication _run] + 928
45 com.apple.GraphicsServices 0x7fff2cba9c8e GSEventRunModal + 139
44 com.apple.CoreFoundation 0x7fff2036b704 CFRunLoopRunSpecific + 562
43 com.apple.CoreFoundation 0x7fff2036c6ca __CFRunLoopRun + 2761
42 com.apple.CoreFoundation 0x7fff20371ed5 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
41 libdispatch.dylib 0x7fff20122c1b _dispatch_main_queue_callback_4CF + 31
40 libdispatch.dylib 0x7fff20123043 _dispatch_main_queue_drain + 1050
39 libdispatch.dylib 0x7fff20115b25 _dispatch_client_callout + 8
38 libdispatch.dylib 0x7fff201148e4 _dispatch_call_block_and_release + 12
37 org.mozilla.ios.Fennec 0x10ff28ae8 thunk for @escaping @callee_guaranteed @Sendable () -> () + 40 <compiler-generated>:0
36 org.mozilla.ios.Fennec 0x11023c10f closure #1 in LaunchScreenViewController.launchWith(launchType:) + 175 LaunchScreenViewController.swift:70
35 org.mozilla.ios.Fennec 0x1101bf61e protocol witness for LaunchFinishedLoadingDelegate.launchWith(launchType:) in conformance SceneCoordinator + 30 <compiler-generated>:0
34 org.mozilla.ios.Fennec 0x1101bde37 SceneCoordinator.launchWith(launchType:) + 119 SceneCoordinator.swift:91
33 org.mozilla.ios.Fennec 0x1101be3a1 SceneCoordinator.startLaunch(with:) + 1009 SceneCoordinator.swift:107
32 org.mozilla.ios.Fennec 0x1106647ed LaunchCoordinator.start(with:) + 269 LaunchCoordinator.swift:33
31 org.mozilla.ios.Fennec 0x110664b65 LaunchCoordinator.presentIntroOnboarding(with:isFullScreen:) + 645 LaunchCoordinator.swift:52
30 org.mozilla.ios.Fennec 0x1104fa532 IntroViewController.__allocating_init(viewModel:themeManager:notificationCenter:userDefaults:) + 66 IntroViewController.swift:0
29 org.mozilla.ios.Fennec 0x1104faae0 IntroViewController.init(viewModel:themeManager:notificationCenter:userDefaults:) + 1440 IntroViewController.swift:72
28 org.mozilla.ios.Fennec 0x1104fe3c4 IntroViewController.applyTheme() + 2276 IntroViewController.swift:191
27 libswiftCore.dylib 0x7fff30a465cd Sequence.forEach(_:) + 413
26 org.mozilla.ios.Fennec 0x1104fe458 closure #1 in IntroViewController.applyTheme() + 72 IntroViewController.swift:191
25 org.mozilla.ios.Fennec 0x11037542b OnboardingCardViewController.applyTheme() + 1163 OnboardingCardViewController.swift:404
24 org.mozilla.ios.Fennec 0x1103743d6 OnboardingCardViewController.setupLinkButton() + 1430 OnboardingCardViewController.swift:366
23 org.mozilla.ios.Fennec 0x110a2bc3c LinkButton.configure(viewModel:) + 604
22 com.apple.UIKitCore 0x7fff256555b8 -[UIView(Hierarchy) layoutBelowIfNeeded] + 1227
21 com.apple.UIKitCore 0x7fff25565f7f -[UIView(AdditionalLayoutSupport) _updateConstraintsAtEngineLevelIfNeededWithViewForVariableChangeNotifications:] + 388
20 com.apple.UIKitCore 0x7fff25564e60 -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededWithViewForVariableChangeNotifications:] + 154
19 com.apple.UIKitCore 0x7fff25563b3c -[UIView(AdditionalLayoutSupport) _withUnsatisfiableConstraintsLoggingSuspendedIfEngineDelegateExists:] + 104
18 com.apple.UIKitCore 0x7fff2556530c __100-[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededWithViewForVariableChangeNotifications:]_block_invoke + 85
17 com.apple.CoreAutoLayout 0x7fff60dc32a7 -[NSISEngine withBehaviors:performModifications:] + 84
16 com.apple.UIKitCore 0x7fff255649f6 -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededCollectingViews:forSecondPass:] + 848
15 com.apple.UIKitCore 0x7fff255649f6 -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededCollectingViews:forSecondPass:] + 848
14 com.apple.UIKitCore 0x7fff255649f6 -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededCollectingViews:forSecondPass:] + 848
13 com.apple.UIKitCore 0x7fff255649f6 -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededCollectingViews:forSecondPass:] + 848
12 com.apple.UIKitCore 0x7fff255649f6 -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededCollectingViews:forSecondPass:] + 848
11 com.apple.UIKitCore 0x7fff255649f6 -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededCollectingViews:forSecondPass:] + 848
10 com.apple.UIKitCore 0x7fff25564b76 -[UIView(AdditionalLayoutSupport) _updateConstraintsIfNeededCollectingViews:forSecondPass:] + 1232
9 com.apple.UIKitCore 0x7fff255643f5 -[UIView(AdditionalLayoutSupport) _sendUpdateConstraintsIfNecessaryForSecondPass:] + 81
8 com.apple.UIKitCore 0x7fff2492ac52 -[UIButton _needsDoubleUpdateConstraintsPass] + 138
7 com.apple.UIKitCore 0x7fff24c59eee -[UIButtonConfigurationVisualProvider hasMultilineText] + 27
6 com.apple.UIKitCore 0x7fff24c59d9a -[UIButtonConfigurationVisualProvider updateConfigurationIfNecessary] + 229
5 org.mozilla.ios.Fennec 0x110a30928 @objc SecondaryRoundedButton.updateConfiguration() + 24
4 org.mozilla.ios.Fennec 0x110a30634 SecondaryRoundedButton.updateConfiguration() + 148
3 libswiftUIKit.dylib 0x7fff59d65ae7 UIButton.configuration.getter + 71
2 libswiftCore.dylib 0x7fff30c9e777 swift_allocObject + 39
1 libswiftCore.dylib 0x7fff30c9e608 swift_slowAlloc + 40
0 libsystem_malloc.dylib 0x7fff2016ed91 _malloc_zone_malloc + 241
====
10 (816 bytes) ROOT CYCLE: <UIKit.ObjCImplWrapper<__C.UIButtonConfiguration> 0x600000641e80> [32]
9 (784 bytes) __strong impl --> ROOT CYCLE: <UIButtonConfiguration 0x600003a0fa00> [256]
3 (112 bytes) __strong _titleTextAttributesTransformer --> ROOT CYCLE: <__NSMallocBlock__ 0x60000087ca50> [48] libswiftUIKit.dylib thunk for @escaping @callee_guaranteed (@guaranteed [NSAttributedStringKey ..."
2 (64 bytes) ROOT CYCLE: <Swift closure context 0x600000641e60> [32]
1 (32 bytes) + 8 --> ROOT CYCLE: 0x600000641d80 [32]
CYCLE BACK TO <UIKit.ObjCImplWrapper<__C.UIButtonConfiguration> 0x600000641e80> [32]
1 (192 bytes) __strong _background --> <UIBackgroundConfiguration 0x600003314240> [192]
3 (128 bytes) __strong _resolvedTitle --> <NSConcreteAttributedString 0x600000641e00> [32]
2 (96 bytes) attributes --> <NSRLEArray 0x600000411c20> [16]
1 (80 bytes) theList --> <NSMutableRLEArray.theList (struct _NSRefCountedRunArray) 0x6000025395e0> [80]
1 (96 bytes) __strong _resolvedSymbolConfig --> <UIImageSymbolConfiguration 0x600002217660> [96]
Expected behavior
No leaks
Actual behavior
Observed retain cycles.
Device & build information
- Device: ? iOS 15.5, iPHone 11
- Build version: ? Latest main branch
- First seen version: ?
Notes
Attachments:
- Leak report: https://github.com/amanjeetsingh150/firefox-ios/blob/fix-memory-leaks/maestro/leaks/suggestions_leak_report.txt#L628](https://github.com/amanjeetsingh150/firefox-ios/blob/fix-memory-leaks/maestro/leaks/suggestions_leak_report.txt#L440)
- Test: https://github.com/amanjeetsingh150/firefox-ios/blob/fix-memory-leaks/maestro/suggestion_visibility.yaml
┆Issue is synchronized with this Jira Task