fix(offline): serialize tileRegionPacks access on main thread, keep OfflineManager alive until tasks complete#4253
Merged
Conversation
…neManager alive until its tasks complete
The loadStylePack/loadTileRegion progress callbacks are delivered on
Mapbox SDK background threads ("com.mapbox.common.MB TileStore RW") and
mutated the tileRegionPacks dictionary concurrently with the main
thread, corrupting it and aborting with "object deallocated with
non-zero retain count" or malloc "pointer being freed was not
allocated". The RCT methods (getPackStatus, resumePackDownload,
pausePackDownload, deletePack) run on the module's background method
queue and touched the same state, as did convertRegionsToJSON's
TileStore callbacks. All of these now hop to the main queue, matching
the completion handlers.
Also keep the function-local OfflineManager alive until both of the
async tasks it started complete: it was deallocated ~0ms after
startLoading returned, before the style pack load finished.
Fixes #4252
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.
Description
Fixes #4252
The SIGABRT reported in #4252 ("object deallocated with non-zero retain count", in a closure in
startLoading) turned out to be a data race ontileRegionPacks: theloadStylePack/loadTileRegionprogress callbacks are delivered on Mapbox SDK background threads (com.mapbox.common.MB TileStore RW) and mutated the dictionary concurrently with the main thread. Crash reports from the reproducer below show both threads inside thetileRegionPackssetter/subscript at the moment of the abort (also seen as malloc "pointer being freed was not allocated"). The progress closures now hop to the main queue, as the completion handlers already did. The RCT entry points that touch the same state (getPackStatus,resumePackDownload,pausePackDownload,deletePack— these run on the module's background method queue) andconvertRegionsToJSON's TileStore callbacks are serialized on main as well.The issue's original finding is also addressed: the function-local
OfflineManagerwas deallocated ~0ms afterstartLoadingreturned (instrumentation showed deinit before the style pack completion in 910/914 packs), sotaskGroup.notifynow holds it viawithExtendedLifetimeuntil both tasks complete.Verification with the reproducer below on the iOS simulator: unfixed build crashed 3 times within minutes (by ~1,400 packs); fixed build ran 10,341 packs in ~9 minutes with no crash, and the manager outlived its tasks in 3,402/3,402 observed packs.
Checklist
CONTRIBUTING.mdyarn generatein the root folder/exampleapp./example)Component to reproduce the issue you're fixing
Hammer reproducer — put into
example/src/examples/BugReportExample.js, open "Bug Report Template", press Start; the unfixed build aborts within a few minutesCrash stacks from the unfixed build (3 aborts within ~7 min)
Main thread aborting while the TileStore thread is in the same dictionary:
And the TileStore thread itself aborting on the corrupted heap: