From 66ea1572c72452824debf726c0703630b26b0f97 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 10 Nov 2020 01:10:00 +0900 Subject: [PATCH] Fix unsafe list manipulation in BeatmapDifficultyCache --- osu.Game/Beatmaps/BeatmapDifficultyCache.cs | 44 +++++++++++++-------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs index eb83c88318..eeb6075ef5 100644 --- a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs +++ b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs @@ -31,7 +31,7 @@ public class BeatmapDifficultyCache : MemoryCachingComponent trackedBindables = new LockedWeakList(); + private readonly WeakList trackedBindables = new WeakList(); [Resolved] private BeatmapManager beatmapManager { get; set; } @@ -59,7 +59,10 @@ protected override void LoadComplete() public IBindable GetBindableDifficulty([NotNull] BeatmapInfo beatmapInfo, CancellationToken cancellationToken = default) { var bindable = createBindable(beatmapInfo, currentRuleset.Value, currentMods.Value, cancellationToken); - trackedBindables.Add(bindable); + + lock (trackedBindables) + trackedBindables.Add(bindable); + return bindable; } @@ -86,7 +89,8 @@ public IBindable GetBindableDifficulty([NotNull] BeatmapInfo bea /// The s to get the difficulty with. /// An optional which stops computing the star difficulty. /// The . - public Task GetDifficultyAsync([NotNull] BeatmapInfo beatmapInfo, [CanBeNull] RulesetInfo rulesetInfo = null, [CanBeNull] IEnumerable mods = null, CancellationToken cancellationToken = default) + public Task GetDifficultyAsync([NotNull] BeatmapInfo beatmapInfo, [CanBeNull] RulesetInfo rulesetInfo = null, [CanBeNull] IEnumerable mods = null, + CancellationToken cancellationToken = default) { // In the case that the user hasn't given us a ruleset, use the beatmap's default ruleset. rulesetInfo ??= beatmapInfo.Ruleset; @@ -148,15 +152,18 @@ public static DifficultyRating GetDifficultyRating(double starRating) /// private void updateTrackedBindables() { - cancelTrackedBindableUpdate(); - trackedUpdateCancellationSource = new CancellationTokenSource(); - - foreach (var b in trackedBindables) + lock (trackedBindables) { - var linkedSource = CancellationTokenSource.CreateLinkedTokenSource(trackedUpdateCancellationSource.Token, b.CancellationToken); - linkedCancellationSources.Add(linkedSource); + cancelTrackedBindableUpdate(); + trackedUpdateCancellationSource = new CancellationTokenSource(); - updateBindable(b, currentRuleset.Value, currentMods.Value, linkedSource.Token); + foreach (var b in trackedBindables) + { + var linkedSource = CancellationTokenSource.CreateLinkedTokenSource(trackedUpdateCancellationSource.Token, b.CancellationToken); + linkedCancellationSources.Add(linkedSource); + + updateBindable(b, currentRuleset.Value, currentMods.Value, linkedSource.Token); + } } } @@ -165,15 +172,18 @@ private void updateTrackedBindables() /// private void cancelTrackedBindableUpdate() { - trackedUpdateCancellationSource?.Cancel(); - trackedUpdateCancellationSource = null; - - if (linkedCancellationSources != null) + lock (trackedBindables) { - foreach (var c in linkedCancellationSources) - c.Dispose(); + trackedUpdateCancellationSource?.Cancel(); + trackedUpdateCancellationSource = null; - linkedCancellationSources.Clear(); + if (linkedCancellationSources != null) + { + foreach (var c in linkedCancellationSources) + c.Dispose(); + + linkedCancellationSources.Clear(); + } } }