-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
Manifest driven EventSources mark all strings as win:UnicodeString in the manifest. This is interpreted by TraceEvent and other pieces of tracing infrastructure as "a null-terminated string". There is a separate type for "counted strings" that isn't used by EventSource.
C#, however, allows for embedded nulls in strings, and String.Length will give the full length of string including the embedded nulls.
EventSource uses String.Length when it is encoding strings, e.g.,
runtime/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs
Lines 1089 to 1091 in c37257f
| descrs[1].DataPointer = (IntPtr)string2Bytes; | |
| descrs[1].Size = ((arg2.Length + 1) * 2); | |
| descrs[1].Reserved = 0; |
This can lead to problems for the parser if there are things in the payload after the string. For example:
public class MySource : EventSource
{
public static MySource Instance = new MySource();
public void MyEvent(int foo, string bar, int baz) => WriteEvent(1, foo, bar, baz);
}
// ...
var myString = "aaa$bbb";
myString = myString.Replace('$', '\0');
MySource.Instance.MyEvent(10, myString, -10);
will result in the following at the reader end:

The event contains the full data:
<Event MSec= "4096.7191" PID="24292" PName="EventSourceNullContent" TID="31320" EventName="MyEvent"
TimeStamp="04/26/21 17:14:07.575276" ID="1" Version="0" Keywords="0x0000F00000000000" TimeStampQPC="9,698,287,562,667" QPCTime="0.100us"
Level="Informational" ProviderName="MySource" ProviderGuid="a61ea624-4944-55fc-c2a8-37838829438d" ClassicProvider="False" ProcessorNumber="7"
Opcode="0" Task="65533" Channel="0" PointerSize="8"
CPU="7" EventIndex="70874" TemplateType="DynamicTraceEventData">
<PrettyPrint>
<Event MSec= "4096.7191" PID="24292" PName="EventSourceNullContent" TID="31320" EventName="MyEvent" ProviderName="MySource" foo="10" bar="aaa" baz="6,422,626"/>
</PrettyPrint>
<Payload Length="24">
0: a 0 0 0 61 0 61 0 | 61 0 0 0 62 0 62 0 ....a.a. a...b.b.
10: 62 0 0 0 f6 ff ff ff | b.......
</Payload>
</Event>
TraceEvent attempts to read a null terminated string, and then interprets the next 4 bytes as the baz parameter which is incorrect.
A potential solution would be to truncate input strings to the first null encountered. I imagine this is a very rare occurrence and the overhead of running String.IndexOf((char)0) should be minimal for the common use case. We could also push and out of band message that an event payload string was truncated.