Repository: dotnet/runtime
File: src/tests/tracing/userevents/common/UserEventsTestRunner.cs (C#)

Code before:
                }
            };
            recordTraceProcess.BeginOutputReadLine();
            recordTraceProcess.ErrorDataReceived += (_, args) =>
            {
                if (!string.IsNullOrEmpty(args.Data))
                {
                    Console.Error.WriteLine($"[record-trace] {args.Data}");
                }
            };
            recordTraceProcess.BeginErrorReadLine();
            Console.WriteLine($"record-trace started with PID: {recordTraceProcess.Id}");

            ProcessStartInfo traceeStartInfo = new();
            
            // NativeAOT tests run the native executable directly.
            // CoreCLR tests run through corerun which loads the managed assembly.
            if (isNativeAot)
            {
                traceeStartInfo.FileName = Environment.ProcessPath 
                    ?? throw new InvalidOperationException("Environment.ProcessPath is null");
                traceeStartInfo.Arguments = "tracee";
            }
            else
            {
                traceeStartInfo.FileName = Process.GetCurrentProcess().MainModule?.FileName 
                    ?? throw new InvalidOperationException("Unable to determine current process executable path");
                traceeStartInfo.Arguments = $"{traceeAssemblyPath} tracee";
            }
            
            traceeStartInfo.WorkingDirectory = userEventsScenarioDir;
            traceeStartInfo.RedirectStandardOutput = true;
            traceeStartInfo.RedirectStandardError = true;

            // record-trace currently only searches /tmp/ for diagnostic ports https://github.com/microsoft/one-collect/issues/183
            string diagnosticPortDir = "/tmp";
            traceeStartInfo.Environment["TMPDIR"] = diagnosticPortDir;

            // Note: record-trace uses perfmap/doublemapper to discover .NET process PIDs and their diagnostic ports.
            // NativeAOT apps do not use doublemapping, so they will not be discovered by record-trace even with TMPDIR set.
            // See https://github.com/microsoft/one-collect/issues/226 for details.

            // TMPDIR is configured on Helix, but the diagnostic port is created outside of Helix's default temp datadisk path.
            // The diagnostic port should be automatically cleaned up when the tracee shuts down, but zombie sockets can be left
            // behind after catastrophic exits. Clean them before launching the tracee to avoid deleting sockets from a reused PID.
            // When https://github.com/microsoft/one-collect/issues/183 is fixed, this and the above TMPDIR should be removed.
            EnsureCleanDiagnosticPorts(diagnosticPortDir);

            Console.WriteLine($"Starting tracee process: {traceeStartInfo.FileName} {traceeStartInfo.Arguments}");
            using Process traceeProcess = Process.Start(traceeStartInfo);
            int traceePid = traceeProcess.Id;

Review comment (suggestion):
@copilot `Process.GetCurrentProcess().MainModule?.FileName` should be same as `Environment.ProcessPath`. Change this to use `Environment.ProcessPath` for all runtime flavors

Code after:
            using Process recordTraceProcess = Process.Start(recordTraceStartInfo);
            recordTraceProcess.OutputDataReceived += (_, args) =>
            {
                if (!string.IsNullOrEmpty(args.Data))
                {
                    Console.WriteLine($"[record-trace] {args.Data}");
                }
            };
            recordTraceProcess.BeginOutputReadLine();
            recordTraceProcess.ErrorDataReceived += (_, args) =>
            {
                if (!string.IsNullOrEmpty(args.Data))
                {
                    Console.Error.WriteLine($"[record-trace] {args.Data}");
                }
            };
            recordTraceProcess.BeginErrorReadLine();
            Console.WriteLine($"record-trace started with PID: {recordTraceProcess.Id}");

            ProcessStartInfo traceeStartInfo = new();
            traceeStartInfo.FileName = Environment.ProcessPath
                ?? throw new InvalidOperationException("Environment.ProcessPath is null");

            // NativeAOT tests run the native executable directly.
            // CoreCLR tests run through corerun which loads the managed assembly.
            if (isNativeAot)
            {
                traceeStartInfo.ArgumentList.Add("tracee");
            }
            else
            {
                // For CoreCLR, construct the path to the assembly
                string assemblyPath = Path.Combine(userEventsScenarioDir, $"{scenarioName}.dll");
                traceeStartInfo.ArgumentList.Add(assemblyPath);
                traceeStartInfo.ArgumentList.Add("tracee");
            }

            traceeStartInfo.WorkingDirectory = userEventsScenarioDir;
            traceeStartInfo.RedirectStandardOutput = true;
            traceeStartInfo.RedirectStandardError = true;

            // record-trace currently only searches /tmp/ for diagnostic ports https://github.com/microsoft/one-collect/issues/183
            string diagnosticPortDir = "/tmp";
            traceeStartInfo.Environment["TMPDIR"] = diagnosticPortDir;

            // TMPDIR is configured on Helix, but the diagnostic port is created outside of Helix's default temp datadisk path.
            // The diagnostic port should be automatically cleaned up when the tracee shuts down, but zombie sockets can be left
            // behind after catastrophic exits. Clean them before launching the tracee to avoid deleting sockets from a reused PID.
            // When https://github.com/microsoft/one-collect/issues/183 is fixed, this and the above TMPDIR should be removed.
            EnsureCleanDiagnosticPorts(diagnosticPortDir);