From bd7245aecbbb8193ab5fb014fbda985b7854bfa6 Mon Sep 17 00:00:00 2001 From: Meivyn <793322+Meivyn@users.noreply.github.com> Date: Thu, 8 Aug 2024 11:30:40 -0400 Subject: [PATCH] Fix potential thread block in `SingleCreationValueCache.GetOrAdd` --- .../Async/SingleCreationValueCache.cs | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/IPA.Loader/Utilities/Async/SingleCreationValueCache.cs b/IPA.Loader/Utilities/Async/SingleCreationValueCache.cs index ea361c55..226b0e06 100644 --- a/IPA.Loader/Utilities/Async/SingleCreationValueCache.cs +++ b/IPA.Loader/Utilities/Async/SingleCreationValueCache.cs @@ -71,7 +71,7 @@ namespace IPA.Utilities.Async #endregion /// - /// Gets a value that indicates whether this cache is empty. + /// Gets a value that indicates whether this cache is empty. /// public bool IsEmpty => dict.IsEmpty; /// @@ -143,10 +143,22 @@ namespace IPA.Utilities.Async var cmp = (wh, default(TValue)); if (!dict.TryAdd(key, cmp)) goto retry; // someone else beat us to the punch, retry getting their value and wait for them - var val = creator(key); - while (!dict.TryUpdate(key, (null, val), cmp)) - throw new InvalidOperationException(); - wh.Set(); + TValue val; + try + { + val = creator(key); + while (!dict.TryUpdate(key, (null, val), cmp)) + throw new InvalidOperationException(); + } + catch + { + dict.TryRemove(key, out _); + throw; + } + finally + { + wh.Set(); + } return val; } }