Skip to content

v5.9.8

Latest

Choose a tag to compare

@github-actions github-actions released this 22 Sep 06:08

Highlights

A stop no longer leaves a NullReferenceException behind.

πŸ› Fixes

  • A finished download could be reported as "Failed β€” Object reference not set to an instance of an object." Both dispatch loops start every chunk task eagerly and then await them one at a time, so a CancelAsync() abandons every chunk the loop had not reached yet. Those chunks are still inside their read loops and still raise progress events, while the download has already run its terminal path β€” which closes the package storage and sets Package.Storage to null. Each progress event writes the auto-resume metadata through that storage, unguarded, so an abandoned chunk threw an NRE; when its cancellation token is no longer the one in force, that NRE becomes the download's error and reaches the consumer through DownloadFileCompleted. The metadata write now reads the storage once and skips it when the download is over β€” resume metadata for a finished transfer is worthless anyway.
  • A Dispose() racing a completion could swallow the completion event entirely. Clear() nulls the internal TaskCompletionSource, and an app that releases its engine as soon as a download ends can run that concurrently with the completion signal. Reporting that a download is over no longer depends on that field still being there.
  • ActiveChunks no longer throws when the semaphore it counts has already been disposed by Clear(); a torn-down download reports no active chunks instead.
  • DownloadPackage.FlushAsync/CloseAsync read Storage once instead of check-then-use, so a flush that races a close cannot dereference null.

πŸ”§ Under the hood

  • StopRaisesNoNullReferenceTest covers the race deterministically (it raises 7 NREs against 5.9.7 and none against this release), and an opt-in soak (RetryAfterStopStressTest, enabled with NRE_STRESS_ITERATIONS) walks stop β†’ dispose β†’ retry across cancel point, chunk count, parallel on/off, server variant and throttled/instant.
  • Fixed a lost-update race in two integration tests that recorded peak progress with a non-atomic Math.Max.

Found from a download manager whose retried-after-stop row was shown as failed even though the file was complete on disk (Downloader.Desktop).

Full Changelog: v5.9.7...v5.9.8