Skip to content

Commit

Permalink
Protect initialization of TraceEventSession.ProviderNameToGuid and
Browse files Browse the repository at this point in the history
TraceEventSession.ProviderGuidToName with a lock to allow for multiple
concurrent callers.

This does not change the concurrency guarantees for TraceEvent, but does
allow for multiple concurrent callers of TraceEventSession.EnableProvider
on different instances of TraceEventSession, where prior to this change
it was possible for this to produce a crash on insertion into the
Dictionary or SortedDictionary.
  • Loading branch information
brianrob committed Oct 19, 2023
1 parent d52d78f commit e76170f
Showing 1 changed file with 37 additions and 20 deletions.
57 changes: 37 additions & 20 deletions src/TraceEvent/TraceEventSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1631,27 +1631,35 @@ internal static SortedDictionary<string, Guid> ProviderNameToGuid
{
if (s_providersByName == null)
{
s_providersByName = new SortedDictionary<string, Guid>(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;

hr = TraceEventNativeMethods.TdhEnumerateProviders(providersDesc, ref buffSize);
if ((hr == 0) && (providersDesc != null))
lock (s_lock)
{
var providers = (TraceEventNativeMethods.TRACE_PROVIDER_INFO*)&providersDesc[1];
for (int i = 0; i < providersDesc->NumberOfProviders; i++)
if (s_providersByName == null)
{
var name = new string((char*)&buffer[providers[i].ProviderNameOffset]);
s_providersByName[name] = providers[i].ProviderGuid;
SortedDictionary<string, Guid> providersByName = new SortedDictionary<string, Guid>(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;

hr = TraceEventNativeMethods.TdhEnumerateProviders(providersDesc, ref buffSize);
if ((hr == 0) && (providersDesc != null))
{
var providers = (TraceEventNativeMethods.TRACE_PROVIDER_INFO*)&providersDesc[1];
for (int i = 0; i < providersDesc->NumberOfProviders; i++)
{
var name = new string((char*)&buffer[providers[i].ProviderNameOffset]);
providersByName[name] = providers[i].ProviderGuid;
}

s_providersByName = providersByName;
}
else
{
Trace.WriteLine("TdhEnumerateProviders failed HR = " + hr);
}
}
}
else
{
Trace.WriteLine("TdhEnumerateProviders failed HR = " + hr);
}
}
return s_providersByName;
}
Expand All @@ -1663,10 +1671,18 @@ internal static Dictionary<Guid, string> ProviderGuidToName
{
if (s_providerNames == null)
{
s_providerNames = new Dictionary<Guid, string>(ProviderNameToGuid.Count);
foreach (var keyValue in ProviderNameToGuid)
lock (s_lock)
{
s_providerNames[keyValue.Value] = keyValue.Key;
if (s_providerNames == null)
{
Dictionary<Guid, string> providerNames = new Dictionary<Guid, string>(ProviderNameToGuid.Count);
foreach (var keyValue in ProviderNameToGuid)
{
providerNames[keyValue.Value] = keyValue.Key;
}

s_providerNames = providerNames;
}
}
}
return s_providerNames;
Expand Down Expand Up @@ -1721,6 +1737,7 @@ private int ComputeEventIdsBufferSize(IList<int> eventIds)
return (eventIds.Count - 1) * 2 + sizeof(TraceEventNativeMethods.EVENT_FILTER_EVENT_ID);
}

private static object s_lock = new object();
private static SortedDictionary<string, Guid> s_providersByName;
private static Dictionary<Guid, string> s_providerNames;

Expand Down

0 comments on commit e76170f

Please # to comment.