diff --git a/src/TraceEvent/TraceEvent.Tests/Regression/ProviderNameToGuidTests.cs b/src/TraceEvent/TraceEvent.Tests/Regression/ProviderNameToGuidTests.cs
new file mode 100644
index 000000000..e0ce4ea82
--- /dev/null
+++ b/src/TraceEvent/TraceEvent.Tests/Regression/ProviderNameToGuidTests.cs
@@ -0,0 +1,26 @@
+using System;
+using Microsoft.Diagnostics.Tracing.Parsers;
+using Microsoft.Diagnostics.Tracing.Session;
+using Xunit;
+
+namespace TraceEventTests
+{
+ public class ProviderNameToGuidTests
+ {
+ ///
+ /// Test that GetProviderGuidByName (which uses ProviderNameToGuid internally) doesn't throw
+ /// when called and correctly returns the GUID for Microsoft-Windows-DotNETRuntime.
+ /// This test validates the fix for the race condition that could cause
+ /// ERROR_INSUFFICIENT_BUFFER (HR 122) crashes.
+ ///
+ [WindowsFact]
+ public void ProviderNameToGuid_DoesNotThrow_AndReturnsCorrectGuid()
+ {
+ // Act - Call ProviderNameToGuid and ensure it doesn't throw
+ Guid actualGuid = TraceEventProviders.GetProviderGuidByName(ClrTraceEventParser.ProviderName);
+
+ // Assert - Verify it matches the expected GUID
+ Assert.Equal(ClrTraceEventParser.ProviderGuid, actualGuid);
+ }
+ }
+}
diff --git a/src/TraceEvent/TraceEventSession.cs b/src/TraceEvent/TraceEventSession.cs
index 9df626f6f..3e1cb624b 100644
--- a/src/TraceEvent/TraceEventSession.cs
+++ b/src/TraceEvent/TraceEventSession.cs
@@ -1760,27 +1760,47 @@ internal static SortedDictionary ProviderNameToGuid
{
SortedDictionary providersByName = new SortedDictionary(StringComparer.OrdinalIgnoreCase);
int buffSize = 0;
- var hr = TraceEventNativeMethods.TdhEnumerateProviders(null, ref buffSize);
- Debug.Assert(hr == 122); // ERROR_INSUFFICIENT_BUFFER
- var buffer = stackalloc byte[buffSize];
- var providersDesc = (TraceEventNativeMethods.PROVIDER_ENUMERATION_INFO*)buffer;
+ byte[] buffer = null;
+ int hr;
- hr = TraceEventNativeMethods.TdhEnumerateProviders(providersDesc, ref buffSize);
- if ((hr == 0) && (providersDesc != null))
+ // Retry loop to handle the case where the buffer size changes between calls
+ // This can happen if providers are registered/unregistered between the two calls
+ for (; ; )
{
- var providers = (TraceEventNativeMethods.TRACE_PROVIDER_INFO*)&providersDesc[1];
- for (int i = 0; i < providersDesc->NumberOfProviders; i++)
+ if (buffSize > 0)
{
- var name = new string((char*)&buffer[providers[i].ProviderNameOffset]);
- providersByName[name] = providers[i].ProviderGuid;
+ buffer = new byte[buffSize];
}
- s_providersByName = providersByName;
- }
- else
- {
- throw new Exception("TdhEnumerateProviders failed HR = " + hr);
+ fixed (byte* bufferPtr = buffer)
+ {
+ var providersDesc = (TraceEventNativeMethods.PROVIDER_ENUMERATION_INFO*)bufferPtr;
+
+ hr = TraceEventNativeMethods.TdhEnumerateProviders(providersDesc, ref buffSize);
+ if (hr == 0)
+ {
+ if (providersDesc != null)
+ {
+ var providers = (TraceEventNativeMethods.TRACE_PROVIDER_INFO*)&providersDesc[1];
+ for (int i = 0; i < providersDesc->NumberOfProviders; i++)
+ {
+ var name = new string((char*)&bufferPtr[providers[i].ProviderNameOffset]);
+ providersByName[name] = providers[i].ProviderGuid;
+ }
+ }
+ break;
+ }
+ }
+
+ // Error 122 means buffer not big enough. For that error we retry, everything else simply fail.
+ if (hr != 122)
+ {
+ throw new Exception("Failed to enumerate trace providers. TdhEnumerateProviders failed HR = " + hr);
+ }
}
+
+ // Always assign providersByName to avoid NullReferenceException on subsequent lookups
+ s_providersByName = providersByName;
}
}
}