Fix unsafe list manipulation in BeatmapDifficultyCache

This commit is contained in:
smoogipoo 2020-11-10 01:10:00 +09:00
parent d7c30f9b42
commit 66ea1572c7
1 changed files with 27 additions and 17 deletions

View File

@ -31,7 +31,7 @@ public class BeatmapDifficultyCache : MemoryCachingComponent<BeatmapDifficultyCa
private readonly ThreadedTaskScheduler updateScheduler = new ThreadedTaskScheduler(1, nameof(BeatmapDifficultyCache)); private readonly ThreadedTaskScheduler updateScheduler = new ThreadedTaskScheduler(1, nameof(BeatmapDifficultyCache));
// All bindables that should be updated along with the current ruleset + mods. // All bindables that should be updated along with the current ruleset + mods.
private readonly LockedWeakList<BindableStarDifficulty> trackedBindables = new LockedWeakList<BindableStarDifficulty>(); private readonly WeakList<BindableStarDifficulty> trackedBindables = new WeakList<BindableStarDifficulty>();
[Resolved] [Resolved]
private BeatmapManager beatmapManager { get; set; } private BeatmapManager beatmapManager { get; set; }
@ -59,7 +59,10 @@ protected override void LoadComplete()
public IBindable<StarDifficulty> GetBindableDifficulty([NotNull] BeatmapInfo beatmapInfo, CancellationToken cancellationToken = default) public IBindable<StarDifficulty> GetBindableDifficulty([NotNull] BeatmapInfo beatmapInfo, CancellationToken cancellationToken = default)
{ {
var bindable = createBindable(beatmapInfo, currentRuleset.Value, currentMods.Value, cancellationToken); var bindable = createBindable(beatmapInfo, currentRuleset.Value, currentMods.Value, cancellationToken);
lock (trackedBindables)
trackedBindables.Add(bindable); trackedBindables.Add(bindable);
return bindable; return bindable;
} }
@ -86,7 +89,8 @@ public IBindable<StarDifficulty> GetBindableDifficulty([NotNull] BeatmapInfo bea
/// <param name="mods">The <see cref="Mod"/>s to get the difficulty with.</param> /// <param name="mods">The <see cref="Mod"/>s to get the difficulty with.</param>
/// <param name="cancellationToken">An optional <see cref="CancellationToken"/> which stops computing the star difficulty.</param> /// <param name="cancellationToken">An optional <see cref="CancellationToken"/> which stops computing the star difficulty.</param>
/// <returns>The <see cref="StarDifficulty"/>.</returns> /// <returns>The <see cref="StarDifficulty"/>.</returns>
public Task<StarDifficulty> GetDifficultyAsync([NotNull] BeatmapInfo beatmapInfo, [CanBeNull] RulesetInfo rulesetInfo = null, [CanBeNull] IEnumerable<Mod> mods = null, CancellationToken cancellationToken = default) public Task<StarDifficulty> GetDifficultyAsync([NotNull] BeatmapInfo beatmapInfo, [CanBeNull] RulesetInfo rulesetInfo = null, [CanBeNull] IEnumerable<Mod> mods = null,
CancellationToken cancellationToken = default)
{ {
// In the case that the user hasn't given us a ruleset, use the beatmap's default ruleset. // In the case that the user hasn't given us a ruleset, use the beatmap's default ruleset.
rulesetInfo ??= beatmapInfo.Ruleset; rulesetInfo ??= beatmapInfo.Ruleset;
@ -147,6 +151,8 @@ public static DifficultyRating GetDifficultyRating(double starRating)
/// Updates all tracked <see cref="BindableStarDifficulty"/> using the current ruleset and mods. /// Updates all tracked <see cref="BindableStarDifficulty"/> using the current ruleset and mods.
/// </summary> /// </summary>
private void updateTrackedBindables() private void updateTrackedBindables()
{
lock (trackedBindables)
{ {
cancelTrackedBindableUpdate(); cancelTrackedBindableUpdate();
trackedUpdateCancellationSource = new CancellationTokenSource(); trackedUpdateCancellationSource = new CancellationTokenSource();
@ -159,11 +165,14 @@ private void updateTrackedBindables()
updateBindable(b, currentRuleset.Value, currentMods.Value, linkedSource.Token); updateBindable(b, currentRuleset.Value, currentMods.Value, linkedSource.Token);
} }
} }
}
/// <summary> /// <summary>
/// Cancels the existing update of all tracked <see cref="BindableStarDifficulty"/> via <see cref="updateTrackedBindables"/>. /// Cancels the existing update of all tracked <see cref="BindableStarDifficulty"/> via <see cref="updateTrackedBindables"/>.
/// </summary> /// </summary>
private void cancelTrackedBindableUpdate() private void cancelTrackedBindableUpdate()
{
lock (trackedBindables)
{ {
trackedUpdateCancellationSource?.Cancel(); trackedUpdateCancellationSource?.Cancel();
trackedUpdateCancellationSource = null; trackedUpdateCancellationSource = null;
@ -176,6 +185,7 @@ private void cancelTrackedBindableUpdate()
linkedCancellationSources.Clear(); linkedCancellationSources.Clear();
} }
} }
}
/// <summary> /// <summary>
/// Creates a new <see cref="BindableStarDifficulty"/> and triggers an initial value update. /// Creates a new <see cref="BindableStarDifficulty"/> and triggers an initial value update.