From 690662c5afe6a832a3f2fbd525af57211f3aef9e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sun, 25 Feb 2024 13:04:44 -0500 Subject: [PATCH] Fix race condition in Windows suspend process --- .../System/WindowsProcessFeatures.cs | 47 ++++++++++++------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/src/Tgstation.Server.Host/System/WindowsProcessFeatures.cs b/src/Tgstation.Server.Host/System/WindowsProcessFeatures.cs index e842bd9db2..f7ad2096a1 100644 --- a/src/Tgstation.Server.Host/System/WindowsProcessFeatures.cs +++ b/src/Tgstation.Server.Host/System/WindowsProcessFeatures.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; @@ -68,28 +69,40 @@ namespace Tgstation.Server.Host.System { ArgumentNullException.ThrowIfNull(process); - process.Refresh(); - foreach (ProcessThread thread in process.Threads) + var suspendedThreadIds = new HashSet(); + bool suspendedNewThreads; + do { - var threadId = (uint)thread.Id; - logger.LogTrace("Suspending thread {threadId}...", threadId); - var pOpenThread = NativeMethods.OpenThread(NativeMethods.ThreadAccess.SuspendResume, false, threadId); - if (pOpenThread == IntPtr.Zero) + suspendedNewThreads = false; + process.Refresh(); + foreach (ProcessThread thread in process.Threads) { - logger.LogDebug(new Win32Exception(), "Failed to open thread {threadId}!", threadId); - continue; - } + var threadId = (uint)thread.Id; - try - { - if (NativeMethods.SuspendThread(pOpenThread) == UInt32.MaxValue) - throw new Win32Exception(); - } - finally - { - NativeMethods.CloseHandle(pOpenThread); + if (!suspendedThreadIds.Add(threadId)) + continue; + + suspendedNewThreads = true; + logger.LogTrace("Suspending thread {threadId}...", threadId); + var pOpenThread = NativeMethods.OpenThread(NativeMethods.ThreadAccess.SuspendResume, false, threadId); + if (pOpenThread == IntPtr.Zero) + { + logger.LogDebug(new Win32Exception(), "Failed to open thread {threadId}!", threadId); + continue; + } + + try + { + if (NativeMethods.SuspendThread(pOpenThread) == UInt32.MaxValue) + throw new Win32Exception(); + } + finally + { + NativeMethods.CloseHandle(pOpenThread); + } } } + while (suspendedNewThreads); } ///