From 06b2d65df7a01f3df3cf52ca48f35114166063f9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Dec 2025 16:32:30 +0000 Subject: [PATCH 1/4] Initial plan From edba6c8bf70b5b8d87d53fa6159810d0306feeb6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Dec 2025 16:44:48 +0000 Subject: [PATCH 2/4] Fix duplicate stringTable elements in instrumentation manifest Added HashSet tracking to prevent duplicate string IDs when generating stringTable entries in GetManifestForRegisteredProvider(). This prevents duplicates for keywords, tasks, opcodes, and enum map values. Co-authored-by: brianrob <6210322+brianrob@users.noreply.github.com> --- src/TraceEvent/RegisteredTraceEventParser.cs | 27 +++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/TraceEvent/RegisteredTraceEventParser.cs b/src/TraceEvent/RegisteredTraceEventParser.cs index eedf36ade..1ce491588 100644 --- a/src/TraceEvent/RegisteredTraceEventParser.cs +++ b/src/TraceEvent/RegisteredTraceEventParser.cs @@ -105,6 +105,9 @@ public static string GetManifestForRegisteredProvider(Guid providerGuid) Dictionary enumIntern = new Dictionary(); StringWriter enumLocalizations = new StringWriter(); + // Track emitted string IDs to prevent duplicates in the stringTable + HashSet emittedStringIds = new HashSet(); + // Any task names used so far Dictionary taskNames = new Dictionary(); // Any es used so far @@ -374,7 +377,11 @@ public static string GetManifestForRegisteredProvider(Guid providerGuid) int value = mapEntries[k].Value; string valueName = new string((char*)(&enumBuffer[mapEntries[k].NameOffset])).Trim(); enumWriter.WriteLine(" ", value, enumName, valueName); - enumLocalizations.WriteLine(" ", enumName, valueName, valueName); + string stringId = string.Format("map_{0}{1}", enumName, valueName); + if (emittedStringIds.Add(stringId)) + { + enumLocalizations.WriteLine(" ", stringId, valueName); + } } if (enumInfo->Flag == MAP_FLAGS.EVENTMAP_INFO_FLAG_MANIFEST_VALUEMAP) { @@ -453,7 +460,11 @@ public static string GetManifestForRegisteredProvider(Guid providerGuid) { manifest.WriteLine(" ", keyValue.Value, keyValue.Value, keyValue.Key); - localizedStrings.WriteLine(" ", keyValue.Value, keyValue.Value); + string stringId = string.Format("keyword_{0}", keyValue.Value); + if (emittedStringIds.Add(stringId)) + { + localizedStrings.WriteLine(" ", stringId, keyValue.Value); + } } manifest.WriteLine(" "); } @@ -464,7 +475,11 @@ public static string GetManifestForRegisteredProvider(Guid providerGuid) var task = tasks[taskValue]; manifest.WriteLine(" ", task.Name, task.Name, taskValue, task.Opcodes == null ? "/" : ""); // If no opcodes, terminate immediately. - localizedStrings.WriteLine(" ", task.Name, task.Name); + string taskStringId = string.Format("task_{0}", task.Name); + if (emittedStringIds.Add(taskStringId)) + { + localizedStrings.WriteLine(" ", taskStringId, task.Name); + } if (task.Opcodes != null) { manifest.WriteLine(">"); @@ -473,7 +488,11 @@ public static string GetManifestForRegisteredProvider(Guid providerGuid) { manifest.WriteLine(" ", keyValue.Value, task.Name, keyValue.Value, keyValue.Key); - localizedStrings.WriteLine(" ", task.Name, keyValue.Value, keyValue.Value); + string opcodeStringId = string.Format("opcode_{0}{1}", task.Name, keyValue.Value); + if (emittedStringIds.Add(opcodeStringId)) + { + localizedStrings.WriteLine(" ", opcodeStringId, keyValue.Value); + } } manifest.WriteLine(" "); manifest.WriteLine(" "); From a0fb4781a564f0bb0e5301e6661a529b31634bfa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Dec 2025 17:00:38 +0000 Subject: [PATCH 3/4] Replace string.Format with string interpolation and add unit test - Replace string.Format calls with string interpolation for stringId generation - Add RegisteredTraceEventParserTests with test for duplicate stringTable entries Co-authored-by: brianrob <6210322+brianrob@users.noreply.github.com> --- src/TraceEvent/RegisteredTraceEventParser.cs | 8 +-- .../RegisteredTraceEventParserTests.cs | 70 +++++++++++++++++++ 2 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 src/TraceEvent/TraceEvent.Tests/Parsing/RegisteredTraceEventParserTests.cs diff --git a/src/TraceEvent/RegisteredTraceEventParser.cs b/src/TraceEvent/RegisteredTraceEventParser.cs index 1ce491588..7ed71299c 100644 --- a/src/TraceEvent/RegisteredTraceEventParser.cs +++ b/src/TraceEvent/RegisteredTraceEventParser.cs @@ -377,7 +377,7 @@ public static string GetManifestForRegisteredProvider(Guid providerGuid) int value = mapEntries[k].Value; string valueName = new string((char*)(&enumBuffer[mapEntries[k].NameOffset])).Trim(); enumWriter.WriteLine(" ", value, enumName, valueName); - string stringId = string.Format("map_{0}{1}", enumName, valueName); + string stringId = $"map_{enumName}{valueName}"; if (emittedStringIds.Add(stringId)) { enumLocalizations.WriteLine(" ", stringId, valueName); @@ -460,7 +460,7 @@ public static string GetManifestForRegisteredProvider(Guid providerGuid) { manifest.WriteLine(" ", keyValue.Value, keyValue.Value, keyValue.Key); - string stringId = string.Format("keyword_{0}", keyValue.Value); + string stringId = $"keyword_{keyValue.Value}"; if (emittedStringIds.Add(stringId)) { localizedStrings.WriteLine(" ", stringId, keyValue.Value); @@ -475,7 +475,7 @@ public static string GetManifestForRegisteredProvider(Guid providerGuid) var task = tasks[taskValue]; manifest.WriteLine(" ", task.Name, task.Name, taskValue, task.Opcodes == null ? "/" : ""); // If no opcodes, terminate immediately. - string taskStringId = string.Format("task_{0}", task.Name); + string taskStringId = $"task_{task.Name}"; if (emittedStringIds.Add(taskStringId)) { localizedStrings.WriteLine(" ", taskStringId, task.Name); @@ -488,7 +488,7 @@ public static string GetManifestForRegisteredProvider(Guid providerGuid) { manifest.WriteLine(" ", keyValue.Value, task.Name, keyValue.Value, keyValue.Key); - string opcodeStringId = string.Format("opcode_{0}{1}", task.Name, keyValue.Value); + string opcodeStringId = $"opcode_{task.Name}{keyValue.Value}"; if (emittedStringIds.Add(opcodeStringId)) { localizedStrings.WriteLine(" ", opcodeStringId, keyValue.Value); diff --git a/src/TraceEvent/TraceEvent.Tests/Parsing/RegisteredTraceEventParserTests.cs b/src/TraceEvent/TraceEvent.Tests/Parsing/RegisteredTraceEventParserTests.cs new file mode 100644 index 000000000..d947146f4 --- /dev/null +++ b/src/TraceEvent/TraceEvent.Tests/Parsing/RegisteredTraceEventParserTests.cs @@ -0,0 +1,70 @@ +using Microsoft.Diagnostics.Tracing.Parsers; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using Xunit; +using Xunit.Abstractions; + +namespace TraceEventTests +{ + public class RegisteredTraceEventParserTests + { + private readonly ITestOutputHelper _output; + + public RegisteredTraceEventParserTests(ITestOutputHelper output) + { + _output = output; + } + + /// + /// Test that GetManifestForRegisteredProvider does not produce duplicate string IDs in the stringTable. + /// This test uses the Microsoft-Windows-DotNETRuntime provider which is known to exist on all Windows machines. + /// + [WindowsFact] + public void GetManifestForRegisteredProvider_NoDuplicateStringTableEntries() + { + // Microsoft-Windows-DotNETRuntime is a well-known provider that exists on all Windows machines + const string providerName = "Microsoft-Windows-DotNETRuntime"; + + // Get the manifest for the provider + string manifest = RegisteredTraceEventParser.GetManifestForRegisteredProvider(providerName); + + Assert.NotNull(manifest); + Assert.NotEmpty(manifest); + + _output.WriteLine($"Generated manifest for {providerName} (length: {manifest.Length} chars)"); + + // Extract all string IDs from the manifest's stringTable + // The format is: + var stringIdPattern = new Regex(@"(); + foreach (Match match in matches) + { + stringIds.Add(match.Groups[1].Value); + } + + _output.WriteLine($"Found {stringIds.Count} string entries in stringTable"); + + // Check for duplicates + var duplicates = stringIds + .GroupBy(id => id) + .Where(g => g.Count() > 1) + .Select(g => new { Id = g.Key, Count = g.Count() }) + .ToList(); + + if (duplicates.Any()) + { + _output.WriteLine($"Found {duplicates.Count} duplicate string IDs:"); + foreach (var dup in duplicates) + { + _output.WriteLine($" '{dup.Id}' appears {dup.Count} times"); + } + } + + // Assert no duplicates exist + Assert.Empty(duplicates); + } + } +} From 5a38b2735685f0579b8e26f6214deb8d28d7f51c Mon Sep 17 00:00:00 2001 From: Brian Robbins Date: Mon, 12 Jan 2026 14:59:04 -0800 Subject: [PATCH 4/4] Switch test to use Microsoft-JScript since it contains duplicates. --- .../Parsing/RegisteredTraceEventParserTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/TraceEvent/TraceEvent.Tests/Parsing/RegisteredTraceEventParserTests.cs b/src/TraceEvent/TraceEvent.Tests/Parsing/RegisteredTraceEventParserTests.cs index d947146f4..f182b97df 100644 --- a/src/TraceEvent/TraceEvent.Tests/Parsing/RegisteredTraceEventParserTests.cs +++ b/src/TraceEvent/TraceEvent.Tests/Parsing/RegisteredTraceEventParserTests.cs @@ -18,13 +18,13 @@ public RegisteredTraceEventParserTests(ITestOutputHelper output) /// /// Test that GetManifestForRegisteredProvider does not produce duplicate string IDs in the stringTable. - /// This test uses the Microsoft-Windows-DotNETRuntime provider which is known to exist on all Windows machines. + /// This test uses the Microsoft-JScript provider which is known to exist on all Windows machines. /// [WindowsFact] public void GetManifestForRegisteredProvider_NoDuplicateStringTableEntries() { - // Microsoft-Windows-DotNETRuntime is a well-known provider that exists on all Windows machines - const string providerName = "Microsoft-Windows-DotNETRuntime"; + // Microsoft-JScript is a well-known provider that exists on all Windows machines + const string providerName = "Microsoft-JScript"; // Get the manifest for the provider string manifest = RegisteredTraceEventParser.GetManifestForRegisteredProvider(providerName);