Skip to content

EventSource should mention some built-in types require special handling #2608

@kevin-montrose

Description

@kevin-montrose

Documentation Request

EventSource does not mention that some built-in .NET types need to be mapped to the types expected by ETW. Presumably this has something to do with the reflection-generated manifests, but I haven't dug in to verify that.

To illustrate the issue, it is easy enough to modify some of the examples in the above link to end up with an event source like:

[EventSource(Name = nameof(CustomEventSource))]
internal class CustomEventSource : EventSource
{
    private const int MyEventId = 123;
	
    internal static readonly CustomEventSource Instance = new CustomEventSource();

    [Event(MyEventId, Version = 1)]
    public unsafe void MyEvent(int someInt, DateTime someDateTime, bool someBool)
    {
        Span<EventData> events = stackalloc EventData[3];
        events[0].DataPointer = (IntPtr)(&someInt);
        events[0].Size = sizeof(int);

        events[1].DataPointer = (IntPtr)(&someDateTime);
        events[1].Size = sizeof(DateTime);

        events[2].DataPointer = (IntPtr)(&someBool);
        events[2].Size = sizeof(bool);

        fixed (EventData* eventsPtr = events)
        {
            WriteEventCore(MyEventId, events.Length, eventsPtr);
        }
    }
}

Which is subtly wrong as DateTime and bool do not map 1-to-1 to the format ETW expects - specifically DateTime must be a FILETIME and bool must be mapped to an int of 1 or 0. bool is particular insidious, as the size mismatch between the passed and expected types can result in data corruption (for the following EventDatas) and potentially reads garbage data off the stack.

A corrected version of the above would be:

[EventSource(Name = nameof(CustomEventSource))]
internal class CustomEventSource : EventSource
{
    private const int MyEventId = 123;
	
    internal static readonly CustomEventSource Instance = new CustomEventSource();

    [Event(MyEventId, Version = 1)]
    public unsafe void MyEvent(int someInt, DateTime someDateTime, bool someBool)
    {
        Span<EventData> events = stackalloc EventData[3];
        events[0].DataPointer = (IntPtr)(&someInt);
        events[0].Size = sizeof(int);

        var someDateTimeAsFileTime = someDateTime.ToFileTimeUtc();
        events[1].DataPointer = (IntPtr)(&someDateTimeAsFileTime);
        events[1].Size = sizeof(long);

        var someBoolAsInt = someBool ? 1 : 0;
        events[2].DataPointer = (IntPtr)(&someBoolAsInt);
        events[2].Size = sizeof(int);

        fixed (EventData* eventsPtr = events)
        {
            WriteEventCore(MyEventId, events.Length, eventsPtr);
        }
    }
}

Ideally, any built-in System.* types that might reasonably be on an event should have an example of how to prepare them for EventData. I don't know how involved that would be, so an acceptable alternative would be to just call out that some types need special handling and a link to the relevant ETW documentation (which might be this).

Previous documentation

There's the existing documentation of the EventSource class which should probably be amended.

There's also ETW's input type remarks which are relevant, though the mapping from those types to .NET types is not always clear.

Metadata

Metadata

Assignees

Labels

documentationDocumentation related issue

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions