Description
There is a rare race that can result in a use-after-free on the native end of EventPipeEventProvider
and potentially the EtwEventProvider
.
If one thread (A) is calling EventSource.Dispose()
, and another is in the process of writing (B), it is possible for the following sequence to occur:
A: (1)Dispose
-> (3)m_eventSourceEnabled = false
-> (4)m_eventPipeProvider.Dispose()
-> (6)m_eventPipeProvider = null
B: (2)if (IsEnabled)
-> (5)use m_eventPipeProvider
EventPipeEventProvider.Dispose()
calls EventPipeEventProvider.EventUnregister()
. This deletes the underlying native structures (the only time EventPipeProvider::m_pEventList
is set to nullptr
). The managed code, does not unset the m_provHandle
member, so if someone got a reference to this managed object, they would have a pointer to freed memory. The managed provider has been marked as disabled, however, not all code paths check that value. Specifically:
which is where we AV in this case. We get here from TraceLoggingEventSource.WriteImpl()
which ends up in NameInfo.GetOrCreateEventHandle()
which calls DefineEvent
on the provider:
I'm still pinning down the exact sequencing of events in the hopes I can create a deterministic repro.
I believe this is the cause for the failures on dotnet/coreclr#28179 and #55240.