Skip to content

Commit dd6bc8c

Browse files
Enhance coreclr processing of event pipe configuration to be able to write the pid of the current process into the nettrace file (#48537)
- Also fix the behavior of get_next_config_value_as_utf8_string to work correctly on coreclr, it was type-punning between a buffer returned by ep_rt_byte_array_alloc and ep_rt_utf8_string_free, which isn't safe in the coreclr implementation
1 parent eb03e0f commit dd6bc8c

File tree

6 files changed

+223
-7
lines changed

6 files changed

+223
-7
lines changed

src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2452,6 +2452,21 @@ ep_rt_utf8_string_dup (const ep_char8_t *str)
24522452
return _strdup (str);
24532453
}
24542454

2455+
static
2456+
inline
2457+
ep_char8_t *
2458+
ep_rt_utf8_string_dup_range (const ep_char8_t *str, const ep_char8_t *strEnd)
2459+
{
2460+
ptrdiff_t byte_len = strEnd - str;
2461+
ep_char8_t *buffer = reinterpret_cast<ep_char8_t *>(malloc(byte_len + 1));
2462+
if (buffer != NULL)
2463+
{
2464+
memcpy (buffer, str, byte_len);
2465+
buffer [byte_len] = '\0';
2466+
}
2467+
return buffer;
2468+
}
2469+
24552470
static
24562471
inline
24572472
ep_char8_t *
@@ -2472,6 +2487,38 @@ ep_rt_utf8_string_strtok (
24722487
format, ...) \
24732488
sprintf_s (reinterpret_cast<char *>(str), static_cast<size_t>(str_len), reinterpret_cast<const char *>(format), __VA_ARGS__)
24742489

2490+
static
2491+
inline
2492+
bool
2493+
ep_rt_utf8_string_replace (
2494+
ep_char8_t **str,
2495+
const ep_char8_t *strSearch,
2496+
const ep_char8_t *strReplacement
2497+
)
2498+
{
2499+
STATIC_CONTRACT_NOTHROW;
2500+
if ((*str) == NULL)
2501+
return false;
2502+
2503+
ep_char8_t* strFound = strstr(*str, strSearch);
2504+
if (strFound != NULL)
2505+
{
2506+
size_t strSearchLen = strlen(strSearch);
2507+
size_t newStrSize = strlen(*str) + strlen(strReplacement) - strSearchLen + 1;
2508+
ep_char8_t *newStr = reinterpret_cast<ep_char8_t *>(malloc(newStrSize));
2509+
if (newStr == NULL)
2510+
{
2511+
*str = NULL;
2512+
return false;
2513+
}
2514+
ep_rt_utf8_string_snprintf(newStr, newStrSize, "%.*s%s%s", (int)(strFound - (*str)), *str, strReplacement, strFound + strSearchLen);
2515+
ep_rt_utf8_string_free(*str);
2516+
*str = newStr;
2517+
return true;
2518+
}
2519+
return false;
2520+
}
2521+
24752522
static
24762523
ep_char16_t *
24772524
ep_rt_utf8_to_utf16_string (

src/mono/mono/eventpipe/ep-rt-mono.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1826,6 +1826,22 @@ ep_rt_utf8_string_dup (const ep_char8_t *str)
18261826
return g_strdup (str);
18271827
}
18281828

1829+
static
1830+
inline
1831+
ep_char8_t *
1832+
ep_rt_utf8_string_dup_range (const ep_char8_t *str, const ep_char8_t *strEnd)
1833+
{
1834+
ptrdiff_t byte_len = strEnd - str;
1835+
ep_char8_t *buffer = g_new(ep_char8_t, byte_len + 1);
1836+
if (buffer != NULL)
1837+
{
1838+
memcpy (buffer, str, byte_len);
1839+
buffer [byte_len] = '\0';
1840+
}
1841+
return buffer;
1842+
}
1843+
1844+
18291845
static
18301846
inline
18311847
ep_char8_t *
@@ -1844,6 +1860,37 @@ ep_rt_utf8_string_strtok (
18441860
format, ...) \
18451861
g_snprintf ((gchar *)str, (gulong)str_len, (const gchar *)format, __VA_ARGS__)
18461862

1863+
static
1864+
inline
1865+
bool
1866+
ep_rt_utf8_string_replace (
1867+
ep_char8_t **str,
1868+
const ep_char8_t *strSearch,
1869+
const ep_char8_t *strReplacement
1870+
)
1871+
{
1872+
if ((*str) == NULL)
1873+
return false;
1874+
1875+
ep_char8_t* strFound = strstr(*str, strSearch);
1876+
if (strFound != NULL)
1877+
{
1878+
size_t strSearchLen = strlen(strSearch);
1879+
size_t newStrSize = strlen(*str) + strlen(strReplacement) - strSearchLen + 1;
1880+
ep_char8_t *newStr = g_new(ep_char8_t, newStrSize);
1881+
if (newStr == NULL)
1882+
{
1883+
*str = NULL;
1884+
return false;
1885+
}
1886+
ep_rt_utf8_string_snprintf(newStr, newStrSize, "%.*s%s%s", (int)(strFound - (*str)), *str, strReplacement, strFound + strSearchLen);
1887+
ep_rt_utf8_string_free(*str);
1888+
*str = newStr;
1889+
return true;
1890+
}
1891+
return false;
1892+
}
1893+
18471894
static
18481895
inline
18491896
ep_char16_t *

src/native/eventpipe/ep-rt.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,10 @@ static
670670
ep_char8_t *
671671
ep_rt_utf8_string_dup (const ep_char8_t *str);
672672

673+
static
674+
ep_char8_t *
675+
ep_rt_utf8_string_dup_range (const ep_char8_t *str, const ep_char8_t *strEnd);
676+
673677
static
674678
ep_char8_t *
675679
ep_rt_utf8_string_strtok (
@@ -682,6 +686,14 @@ ep_rt_utf8_string_strtok (
682686
str_len, \
683687
format, ...) ep_redefine
684688

689+
static
690+
inline bool
691+
ep_rt_utf8_string_replace (
692+
ep_char8_t **str,
693+
const ep_char8_t *strSearch,
694+
const ep_char8_t *strReplacement
695+
);
696+
685697
static
686698
ep_char16_t *
687699
ep_rt_utf8_to_utf16_string (

src/native/eventpipe/ep.c

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -729,20 +729,17 @@ get_next_config_value_as_utf8_string (const ep_char8_t **data)
729729
{
730730
EP_ASSERT (data != NULL);
731731

732-
uint8_t *buffer = NULL;
732+
ep_char8_t *buffer = NULL;
733733

734734
const ep_char8_t *start = NULL;
735735
const ep_char8_t *end = NULL;
736736
*data = get_next_config_value (*data, &start, &end);
737737

738738
ptrdiff_t byte_len = end - start;
739-
if (byte_len != 0) {
740-
buffer = ep_rt_byte_array_alloc (byte_len + 1);
741-
memcpy (buffer, start, byte_len);
742-
buffer [byte_len] = '\0';
743-
}
739+
if (byte_len != 0)
740+
buffer = ep_rt_utf8_string_dup_range(start, end);
744741

745-
return (ep_char8_t *)buffer;
742+
return buffer;
746743
}
747744

748745
static
@@ -792,6 +789,22 @@ enable_default_session_via_env_variables (void)
792789
if (ep_rt_config_value_get_enable ()) {
793790
ep_config = ep_rt_config_value_get_config ();
794791
ep_config_output_path = ep_rt_config_value_get_output_path ();
792+
793+
ep_char8_t pidStr[24];
794+
ep_rt_utf8_string_snprintf(pidStr, EP_ARRAY_SIZE (pidStr), "%u", (unsigned)ep_rt_current_process_get_id());
795+
796+
while (true)
797+
{
798+
if (ep_rt_utf8_string_replace(&ep_config_output_path, "{pid}", pidStr))
799+
{
800+
// In case there is a second use of {pid} in the output path
801+
continue;
802+
}
803+
804+
// No more instances of {pid} in the OutputPath
805+
break;
806+
}
807+
795808
ep_circular_mb = ep_rt_config_value_get_circular_mb ();
796809
output_path = NULL;
797810

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Diagnostics;
6+
using System.IO;
7+
using System.Runtime.InteropServices;
8+
using System.Threading;
9+
10+
class NameConfigWithPid
11+
{
12+
static int Main(string[] args)
13+
{
14+
if (args.Length > 0 && args[0] == "waitforinput")
15+
{
16+
Console.Error.WriteLine("WaitingForInput in ErrorStream");
17+
Console.WriteLine("WaitingForInput");
18+
Console.ReadLine();
19+
return 100;
20+
}
21+
else
22+
{
23+
Process process = null;
24+
try
25+
{
26+
process = new Process();
27+
}
28+
catch (PlatformNotSupportedException)
29+
{
30+
// For platforms that do not support launching child processes, simply succeed the test
31+
return 100;
32+
}
33+
34+
string corerun = Path.Combine(Environment.GetEnvironmentVariable("CORE_ROOT"), "corerun");
35+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
36+
corerun = corerun + ".exe";
37+
38+
// Use dll directory as temp directory
39+
string tempDir = Path.GetDirectoryName(typeof(NameConfigWithPid).Assembly.Location);
40+
string outputPathBaseName = $"eventPipeStream{Thread.CurrentThread.ManagedThreadId}_{(ulong)Stopwatch.GetTimestamp()}";
41+
string outputPathPattern = Path.Combine(tempDir, outputPathBaseName + "_{pid}_{pid}.nettrace");
42+
43+
process.StartInfo.FileName = corerun;
44+
process.StartInfo.Arguments = typeof(NameConfigWithPid).Assembly.Location + " waitforinput";
45+
process.StartInfo.UseShellExecute = false;
46+
process.StartInfo.RedirectStandardInput = true;
47+
process.StartInfo.RedirectStandardError = true;
48+
49+
process.StartInfo.Environment.Add("COMPlus_EnableEventPipe", "1");
50+
process.StartInfo.Environment.Add("COMPlus_EventPipeConfig", "Microsoft-Windows-DotNETRuntime:4c14fccbd:4");
51+
process.StartInfo.Environment.Add("COMPlus_EventPipeOutputPath", outputPathPattern);
52+
53+
process.Start();
54+
55+
process.StandardError.ReadLine();
56+
uint pid = (uint)process.Id;
57+
string expectedPath = outputPathPattern.Replace("{pid}", pid.ToString());
58+
59+
process.StandardInput.WriteLine("input");
60+
process.WaitForExit();
61+
if (!File.Exists(expectedPath))
62+
{
63+
Console.WriteLine($"{expectedPath} not found");
64+
return 1;
65+
}
66+
else
67+
{
68+
Console.WriteLine($"{expectedPath} found");
69+
for (int i = 0; i < 20; i++)
70+
{
71+
try
72+
{
73+
if (File.Exists(expectedPath))
74+
File.Delete(expectedPath);
75+
return 100;
76+
}
77+
catch { }
78+
Thread.Sleep(1000);
79+
}
80+
Console.WriteLine($"Unable to delete {expectedPath}");
81+
return 2;
82+
}
83+
}
84+
}
85+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>exe</OutputType>
4+
<CLRTestKind>BuildAndRun</CLRTestKind>
5+
<CLRTestPriority>0</CLRTestPriority>
6+
<UnloadabilityIncompatible>true</UnloadabilityIncompatible>
7+
<GCStressIncompatible>true</GCStressIncompatible>
8+
</PropertyGroup>
9+
<ItemGroup>
10+
<Compile Include="$(MSBuildProjectName).cs" />
11+
</ItemGroup>
12+
</Project>

0 commit comments

Comments
 (0)