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

Fix race condition in ImageDownloader #4587

Closed
wants to merge 4 commits into from

Conversation

azarovalex
Copy link
Contributor

@azarovalex azarovalex commented Jan 22, 2024

ImageDownloader uses a custom NSOperation subclass to asynchronously download images.

Instead of overriding isConcurrent flag, this subclass has to override isAsynchronous flag. isConcurrent is a legacy flag, from the tests I did it seems it's never called by the system.
It seems like right now the fact that we don't correctly set isAsynchronous can lead to crashes in some cases because by default all NSOperations are considered synchronous and iOS can deallocate them before the download is actually finished. This should be fixed by correctly marking our NSOperation as isAsynchronous == true.

I also fixed another potential issue in ImageDownloader where we add a completion handler to an operation only after adding this operation to a queue, in theory this might lead to a race, though I think this could never cause issues in production.

Another issue yet unfixed is:

*** MapboxNavigation.ImageDownloadOperation 0x7b440028ff00 went isFinished=YES without being started by the queue it is in

It happens because our custom subclass of NSOperation doesn't handle correctly a state when it's cancelled before NSOperationQueue started it.

@azarovalex azarovalex requested a review from a team as a code owner January 22, 2024 22:31
@@ -6,7 +6,7 @@ typealias CachedResponseCompletionHandler = (CachedURLResponse?, Error?) -> Void
typealias ImageDownloadCompletionHandler = (DownloadError?) -> Void

protocol ReentrantImageDownloader {
func download(with url: URL, completion: CachedResponseCompletionHandler?) -> Void
func download(with url: URL, completion: @escaping CachedResponseCompletionHandler) -> Void
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't see why we would ever want completion to be nil, changed to non-nil.

Copy link

codecov bot commented Jan 22, 2024

Codecov Report

Attention: 1 lines in your changes are missing coverage. Please review.

Comparison is base (ce064ed) 59.79% compared to head (6d80da4) 1.07%.

❗ Current head 6d80da4 differs from pull request most recent head c518624. Consider uploading reports for the commit c518624 to get more accurate results

Impacted file tree graph

@@            Coverage Diff             @@
##             main   #4587       +/-   ##
==========================================
- Coverage   59.79%   1.07%   -58.72%     
==========================================
  Files         189     189               
  Lines       21218   21215        -3     
==========================================
- Hits        12687     228    -12459     
- Misses       8531   20987    +12456     
Files Coverage Δ
Sources/MapboxNavigation/ImageDownloader.swift 84.81% <100.00%> (-13.98%) ⬇️
Sources/MapboxNavigation/ImageDownload.swift 95.55% <0.00%> (+1.48%) ⬆️

... and 149 files with indirect coverage changes

@azarovalex
Copy link
Contributor Author

Closing in favor of #4588

@azarovalex azarovalex closed this Jan 23, 2024
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.

1 participant