diff --git a/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h b/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h index 109d77a704d3da..84712e91301047 100644 --- a/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h +++ b/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h @@ -2452,6 +2452,21 @@ ep_rt_utf8_string_dup (const ep_char8_t *str) return _strdup (str); } +static +inline +ep_char8_t * +ep_rt_utf8_string_dup_range (const ep_char8_t *str, const ep_char8_t *strEnd) +{ + ptrdiff_t byte_len = strEnd - str; + ep_char8_t *buffer = reinterpret_cast(malloc(byte_len + 1)); + if (buffer != NULL) + { + memcpy (buffer, str, byte_len); + buffer [byte_len] = '\0'; + } + return buffer; +} + static inline ep_char8_t * @@ -2472,6 +2487,38 @@ ep_rt_utf8_string_strtok ( format, ...) \ sprintf_s (reinterpret_cast(str), static_cast(str_len), reinterpret_cast(format), __VA_ARGS__) +static +inline +bool +ep_rt_utf8_string_replace ( + ep_char8_t **str, + const ep_char8_t *strSearch, + const ep_char8_t *strReplacement +) +{ + STATIC_CONTRACT_NOTHROW; + if ((*str) == NULL) + return false; + + ep_char8_t* strFound = strstr(*str, strSearch); + if (strFound != NULL) + { + size_t strSearchLen = strlen(strSearch); + size_t newStrSize = strlen(*str) + strlen(strReplacement) - strSearchLen + 1; + ep_char8_t *newStr = reinterpret_cast(malloc(newStrSize)); + if (newStr == NULL) + { + *str = NULL; + return false; + } + ep_rt_utf8_string_snprintf(newStr, newStrSize, "%.*s%s%s", (int)(strFound - (*str)), *str, strReplacement, strFound + strSearchLen); + ep_rt_utf8_string_free(*str); + *str = newStr; + return true; + } + return false; +} + static ep_char16_t * ep_rt_utf8_to_utf16_string ( diff --git a/src/mono/mono/eventpipe/ep-rt-mono.h b/src/mono/mono/eventpipe/ep-rt-mono.h index 97b78f41ea1260..4d4704ea7efbc2 100644 --- a/src/mono/mono/eventpipe/ep-rt-mono.h +++ b/src/mono/mono/eventpipe/ep-rt-mono.h @@ -1826,6 +1826,22 @@ ep_rt_utf8_string_dup (const ep_char8_t *str) return g_strdup (str); } +static +inline +ep_char8_t * +ep_rt_utf8_string_dup_range (const ep_char8_t *str, const ep_char8_t *strEnd) +{ + ptrdiff_t byte_len = strEnd - str; + ep_char8_t *buffer = g_new(ep_char8_t, byte_len + 1); + if (buffer != NULL) + { + memcpy (buffer, str, byte_len); + buffer [byte_len] = '\0'; + } + return buffer; +} + + static inline ep_char8_t * @@ -1844,6 +1860,37 @@ ep_rt_utf8_string_strtok ( format, ...) \ g_snprintf ((gchar *)str, (gulong)str_len, (const gchar *)format, __VA_ARGS__) +static +inline +bool +ep_rt_utf8_string_replace ( + ep_char8_t **str, + const ep_char8_t *strSearch, + const ep_char8_t *strReplacement +) +{ + if ((*str) == NULL) + return false; + + ep_char8_t* strFound = strstr(*str, strSearch); + if (strFound != NULL) + { + size_t strSearchLen = strlen(strSearch); + size_t newStrSize = strlen(*str) + strlen(strReplacement) - strSearchLen + 1; + ep_char8_t *newStr = g_new(ep_char8_t, newStrSize); + if (newStr == NULL) + { + *str = NULL; + return false; + } + ep_rt_utf8_string_snprintf(newStr, newStrSize, "%.*s%s%s", (int)(strFound - (*str)), *str, strReplacement, strFound + strSearchLen); + ep_rt_utf8_string_free(*str); + *str = newStr; + return true; + } + return false; +} + static inline ep_char16_t * diff --git a/src/native/eventpipe/ep-rt.h b/src/native/eventpipe/ep-rt.h index 07c85a2e4eb0a4..6b2d40e4dfe478 100644 --- a/src/native/eventpipe/ep-rt.h +++ b/src/native/eventpipe/ep-rt.h @@ -670,6 +670,10 @@ static ep_char8_t * ep_rt_utf8_string_dup (const ep_char8_t *str); +static +ep_char8_t * +ep_rt_utf8_string_dup_range (const ep_char8_t *str, const ep_char8_t *strEnd); + static ep_char8_t * ep_rt_utf8_string_strtok ( @@ -682,6 +686,14 @@ ep_rt_utf8_string_strtok ( str_len, \ format, ...) ep_redefine +static +inline bool +ep_rt_utf8_string_replace ( + ep_char8_t **str, + const ep_char8_t *strSearch, + const ep_char8_t *strReplacement +); + static ep_char16_t * ep_rt_utf8_to_utf16_string ( diff --git a/src/native/eventpipe/ep.c b/src/native/eventpipe/ep.c index b3588ada5e22e4..5517c7d98fcc75 100644 --- a/src/native/eventpipe/ep.c +++ b/src/native/eventpipe/ep.c @@ -729,20 +729,17 @@ get_next_config_value_as_utf8_string (const ep_char8_t **data) { EP_ASSERT (data != NULL); - uint8_t *buffer = NULL; + ep_char8_t *buffer = NULL; const ep_char8_t *start = NULL; const ep_char8_t *end = NULL; *data = get_next_config_value (*data, &start, &end); ptrdiff_t byte_len = end - start; - if (byte_len != 0) { - buffer = ep_rt_byte_array_alloc (byte_len + 1); - memcpy (buffer, start, byte_len); - buffer [byte_len] = '\0'; - } + if (byte_len != 0) + buffer = ep_rt_utf8_string_dup_range(start, end); - return (ep_char8_t *)buffer; + return buffer; } static @@ -792,6 +789,22 @@ enable_default_session_via_env_variables (void) if (ep_rt_config_value_get_enable ()) { ep_config = ep_rt_config_value_get_config (); ep_config_output_path = ep_rt_config_value_get_output_path (); + + ep_char8_t pidStr[24]; + ep_rt_utf8_string_snprintf(pidStr, EP_ARRAY_SIZE (pidStr), "%u", (unsigned)ep_rt_current_process_get_id()); + + while (true) + { + if (ep_rt_utf8_string_replace(&ep_config_output_path, "{pid}", pidStr)) + { + // In case there is a second use of {pid} in the output path + continue; + } + + // No more instances of {pid} in the OutputPath + break; + } + ep_circular_mb = ep_rt_config_value_get_circular_mb (); output_path = NULL; diff --git a/src/tests/tracing/eventpipe/complus_config/name_config_with_pid.cs b/src/tests/tracing/eventpipe/complus_config/name_config_with_pid.cs new file mode 100644 index 00000000000000..41b5421ec4c576 --- /dev/null +++ b/src/tests/tracing/eventpipe/complus_config/name_config_with_pid.cs @@ -0,0 +1,85 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; +using System.Threading; + +class NameConfigWithPid +{ + static int Main(string[] args) + { + if (args.Length > 0 && args[0] == "waitforinput") + { + Console.Error.WriteLine("WaitingForInput in ErrorStream"); + Console.WriteLine("WaitingForInput"); + Console.ReadLine(); + return 100; + } + else + { + Process process = null; + try + { + process = new Process(); + } + catch (PlatformNotSupportedException) + { + // For platforms that do not support launching child processes, simply succeed the test + return 100; + } + + string corerun = Path.Combine(Environment.GetEnvironmentVariable("CORE_ROOT"), "corerun"); + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + corerun = corerun + ".exe"; + + // Use dll directory as temp directory + string tempDir = Path.GetDirectoryName(typeof(NameConfigWithPid).Assembly.Location); + string outputPathBaseName = $"eventPipeStream{Thread.CurrentThread.ManagedThreadId}_{(ulong)Stopwatch.GetTimestamp()}"; + string outputPathPattern = Path.Combine(tempDir, outputPathBaseName + "_{pid}_{pid}.nettrace"); + + process.StartInfo.FileName = corerun; + process.StartInfo.Arguments = typeof(NameConfigWithPid).Assembly.Location + " waitforinput"; + process.StartInfo.UseShellExecute = false; + process.StartInfo.RedirectStandardInput = true; + process.StartInfo.RedirectStandardError = true; + + process.StartInfo.Environment.Add("COMPlus_EnableEventPipe", "1"); + process.StartInfo.Environment.Add("COMPlus_EventPipeConfig", "Microsoft-Windows-DotNETRuntime:4c14fccbd:4"); + process.StartInfo.Environment.Add("COMPlus_EventPipeOutputPath", outputPathPattern); + + process.Start(); + + process.StandardError.ReadLine(); + uint pid = (uint)process.Id; + string expectedPath = outputPathPattern.Replace("{pid}", pid.ToString()); + + process.StandardInput.WriteLine("input"); + process.WaitForExit(); + if (!File.Exists(expectedPath)) + { + Console.WriteLine($"{expectedPath} not found"); + return 1; + } + else + { + Console.WriteLine($"{expectedPath} found"); + for (int i = 0; i < 20; i++) + { + try + { + if (File.Exists(expectedPath)) + File.Delete(expectedPath); + return 100; + } + catch { } + Thread.Sleep(1000); + } + Console.WriteLine($"Unable to delete {expectedPath}"); + return 2; + } + } + } +} diff --git a/src/tests/tracing/eventpipe/complus_config/name_config_with_pid.csproj b/src/tests/tracing/eventpipe/complus_config/name_config_with_pid.csproj new file mode 100644 index 00000000000000..8104b7a93b6fd1 --- /dev/null +++ b/src/tests/tracing/eventpipe/complus_config/name_config_with_pid.csproj @@ -0,0 +1,12 @@ + + + exe + BuildAndRun + 0 + true + true + + + + +