From 7bc41fe9f5b195d55d79dec02de3fb2eb2bcce13 Mon Sep 17 00:00:00 2001 From: Ben Russell Date: Thu, 14 Nov 2024 13:55:45 -0600 Subject: [PATCH] Make SqlDependencyProcessDispatcherStorage safe! --- ...ependencyProcessDispatcherStorage.netfx.cs | 40 ++++++------------- 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/src/Interop/Windows/Sni/SqlDependencyProcessDispatcherStorage.netfx.cs b/src/Microsoft.Data.SqlClient/src/Interop/Windows/Sni/SqlDependencyProcessDispatcherStorage.netfx.cs index bbeda47473..dddfcb5e07 100644 --- a/src/Microsoft.Data.SqlClient/src/Interop/Windows/Sni/SqlDependencyProcessDispatcherStorage.netfx.cs +++ b/src/Microsoft.Data.SqlClient/src/Interop/Windows/Sni/SqlDependencyProcessDispatcherStorage.netfx.cs @@ -8,27 +8,24 @@ using System.Diagnostics; using System.Runtime.InteropServices; using System.Runtime.Versioning; -using System.Threading; namespace Interop.Windows.Sni { - internal unsafe class SqlDependencyProcessDispatcherStorage + internal class SqlDependencyProcessDispatcherStorage { - private static void* s_data; + private static readonly object s_lockObj = new(); + private static IntPtr s_data; private static int s_size; - private static volatile int s_lock; // Int used for a spin-lock. [ResourceExposure(ResourceScope.Process)] // SxS: there is no way to set scope = Instance, using Process which is wider [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)] public static byte[] NativeGetData() { - IntPtr ptr = (IntPtr)s_data; - byte[] result = null; - if (ptr != IntPtr.Zero) + if (s_data != IntPtr.Zero) { result = new byte[s_size]; - Marshal.Copy(ptr, result, 0, s_size); + Marshal.Copy(s_data, result, 0, s_size); } return result; @@ -38,29 +35,18 @@ public static byte[] NativeGetData() [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)] internal static void NativeSetData(byte[] data) { - fixed (byte* pDispatcher = data) + lock (s_lockObj) { - while (Interlocked.CompareExchange(ref s_lock, 1, 0) != 0) + if (s_data == IntPtr.Zero) { - // Spin until we have the lock. - Thread.Sleep(50); // Sleep with short-timeout to prevent starvation. - } - Trace.Assert(s_lock == 1); // Now that we have the lock, lock should be equal to 1. - - if (s_data == null) - { - s_data = Marshal.AllocHGlobal(data.Length).ToPointer(); - - Trace.Assert(s_data != null); - - Buffer.MemoryCopy(pDispatcher, s_data, data.Length, data.Length); - - Trace.Assert(0 == s_size); // Size should still be zero at this point. + s_data = Marshal.AllocHGlobal(data.Length); + Trace.Assert(s_data != IntPtr.Zero); + + Marshal.Copy(data, 0, s_data, data.Length); + + Trace.Assert(s_size == 0); // Size should still be zero at this point s_size = data.Length; } - - int result = Interlocked.CompareExchange(ref s_lock, 0, 1); - Trace.Assert(1 == result); // The release of the lock should have been successful. } } }