/// <inheritdoc /> public virtual async Task <SandboxedProcessResult> GetResultAsync() { Contract.Requires(Started); // 1: wait until process exits or process timeout is reached LogProcessState("Waiting for process to exit"); var finishedTask = await Task.WhenAny(Task.Delay(ProcessInfo.Timeout.Value), WhenExited); m_exitTime = DateTime.UtcNow; // 2: kill process if timed out var timedOut = finishedTask != WhenExited; if (timedOut) { LogProcessState($"Process timed out after {ProcessInfo.Timeout.Value}; it will be forcefully killed."); await KillAsync(); } // 3: wait for reports to be all received LogProcessState("Waiting for reports to be received"); var reports = await GetReportsAsync(); m_reportsReceivedTime = DateTime.UtcNow; reports?.Freeze(); // 4: wait for stdout and stderr to be flushed LogProcessState("Waiting for stdout and stderr to be flushed"); await Task.WhenAll(m_stdoutFlushedTcs.Task, m_stderrFlushedTcs.Task); var reportFileAccesses = ProcessInfo.FileAccessManifest?.ReportFileAccesses == true; var fileAccesses = reportFileAccesses ? (reports?.FileAccesses ?? s_emptyFileAccessesSet) : null; return(new SandboxedProcessResult { ExitCode = timedOut ? ExitCodes.Timeout : Process.ExitCode, Killed = Killed, TimedOut = timedOut, HasDetoursInjectionFailures = HasSandboxFailures, StandardOutput = m_output.Freeze(), StandardError = m_error.Freeze(), HasReadWriteToReadFileAccessRequest = reports?.HasReadWriteToReadFileAccessRequest ?? false, AllUnexpectedFileAccesses = reports?.FileUnexpectedAccesses ?? s_emptyFileAccessesSet, FileAccesses = fileAccesses, DetouringStatuses = reports?.ProcessDetoursStatuses, ExplicitlyReportedFileAccesses = reports?.ExplicitlyReportedFileAccesses, Processes = CoalesceProcesses(reports?.Processes), MessageProcessingFailure = reports?.MessageProcessingFailure, DumpCreationException = m_dumpCreationException, DumpFileDirectory = ProcessInfo.TimeoutDumpDirectory, PrimaryProcessTimes = GetProcessTimes(), SurvivingChildProcesses = CoalesceProcesses(GetSurvivingChildProcesses()) }); }
/// <inheritdoc /> public async Task <SandboxedProcessResult> GetResultAsync() { Contract.Requires(Started); SandboxedProcessReports reports = null; await m_processExecutor.WaitForExitAsync(); if (m_processExecutor.Killed) { // call here this.KillAsync() because a subclass may override it // to do some extra processing when a process is killed await KillAsync(); } LogProcessState("Waiting for reports to be received"); reports = await GetReportsAsync(); m_reportsReceivedTime = DateTime.UtcNow; reports?.Freeze(); await m_processExecutor.WaitForStdOutAndStdErrAsync(); var reportFileAccesses = ProcessInfo.FileAccessManifest?.ReportFileAccesses == true; var fileAccesses = reportFileAccesses ? (reports?.FileAccesses ?? s_emptyFileAccessesSet) : null; return(new SandboxedProcessResult { ExitCode = m_processExecutor.TimedOut ? ExitCodes.Timeout : Process.ExitCode, Killed = Killed, TimedOut = m_processExecutor.TimedOut, HasDetoursInjectionFailures = HasSandboxFailures, JobAccountingInformation = GetJobAccountingInfo(), StandardOutput = m_output.Freeze(), StandardError = m_error.Freeze(), HasReadWriteToReadFileAccessRequest = reports?.HasReadWriteToReadFileAccessRequest ?? false, AllUnexpectedFileAccesses = reports?.FileUnexpectedAccesses ?? s_emptyFileAccessesSet, FileAccesses = fileAccesses, DetouringStatuses = reports?.ProcessDetoursStatuses, ExplicitlyReportedFileAccesses = reports?.ExplicitlyReportedFileAccesses, Processes = CoalesceProcesses(reports?.Processes), MessageProcessingFailure = reports?.MessageProcessingFailure, DumpCreationException = m_dumpCreationException, DumpFileDirectory = ProcessInfo.TimeoutDumpDirectory, PrimaryProcessTimes = GetProcessTimes(), SurvivingChildProcesses = CoalesceProcesses(GetSurvivingChildProcesses()) }); }
/// <inheritdoc /> public virtual async Task <SandboxedProcessResult> GetResultAsync() { Contract.Requires(Started); var finishedTask = await Task.WhenAny(Task.Delay(ProcessInfo.Timeout.Value), Completion); var timedOut = finishedTask != Completion; if (timedOut) { LogDebugProcessState("Process timed out"); await KillAsync(); } var reports = await GetReportsAsync(); reports?.Freeze(); var reportFileAccesses = ProcessInfo.FileAccessManifest?.ReportFileAccesses == true; var fileAccesses = reportFileAccesses ? (reports?.FileAccesses ?? s_emptyFileAccessesSet) : null; return(new SandboxedProcessResult { ExitCode = timedOut ? ExitCodes.Timeout : Process.ExitCode, Killed = Killed, TimedOut = timedOut, HasDetoursInjectionFailures = HasSandboxFailures, StandardOutput = m_output.Freeze(), StandardError = m_error.Freeze(), HasReadWriteToReadFileAccessRequest = reports?.HasReadWriteToReadFileAccessRequest ?? false, AllUnexpectedFileAccesses = reports?.FileUnexpectedAccesses ?? s_emptyFileAccessesSet, FileAccesses = fileAccesses, DetouringStatuses = reports?.ProcessDetoursStatuses, ExplicitlyReportedFileAccesses = reports?.ExplicitlyReportedFileAccesses, Processes = CoalesceProcesses(reports?.Processes), MessageProcessingFailure = reports?.MessageProcessingFailure, DumpCreationException = m_dumpCreationException, DumpFileDirectory = ProcessInfo.TimeoutDumpDirectory, PrimaryProcessTimes = GetProcessTimes(), SurvivingChildProcesses = CoalesceProcesses(GetSurvivingChildProcesses()) }); }
private async Task OnProcessExited() { // Wait until all incoming report messages from the detoured process have been handled. await WaitUntilReportEof(m_detouredProcess.Killed); // Ensure no further modifications to the report m_reports?.Freeze(); // We can get extended accounting information (peak memory, etc. rolled up for the entire process tree) if this process was wrapped in a job. JobObject.AccountingInformation?jobAccountingInformation = null; JobObject jobObject = m_detouredProcess.GetJobObject(); if (jobObject != null) { jobAccountingInformation = jobObject.GetAccountingInformation(); } ProcessTimes primaryProcessTimes = m_detouredProcess.GetTimesForPrimaryProcess(); IOException standardInputException = null; try { await m_standardInputTcs.Task; } catch (IOException ex) { standardInputException = ex; } // Construct result; note that the process is expected to have exited at this point, even if we decided to forcefully kill it // (this callback is always a result of the process handle being signaled). int exitCode = 0; if (m_reports?.MessageProcessingFailure != null) { exitCode = ExitCodes.MessageProcessingFailure; } else { Contract.Assert(m_detouredProcess.HasExited, "Detoured process has not been marked as exited"); exitCode = m_detouredProcess.GetExitCode(); } SandboxedProcessResult result = new SandboxedProcessResult { // If there is a message parsing failure, fail the pip. ExitCode = exitCode, Killed = m_detouredProcess.Killed, TimedOut = m_detouredProcess.TimedOut, HasDetoursInjectionFailures = m_detouredProcess.HasDetoursInjectionFailures, SurvivingChildProcesses = m_survivingChildProcesses?.Values.ToArray(), PrimaryProcessTimes = primaryProcessTimes, JobAccountingInformation = jobAccountingInformation, StandardOutput = m_output.Freeze(), StandardError = m_error.Freeze(), AllUnexpectedFileAccesses = m_reports?.FileUnexpectedAccesses, FileAccesses = m_reports?.FileAccesses, DetouringStatuses = m_reports?.ProcessDetoursStatuses, ExplicitlyReportedFileAccesses = m_reports?.ExplicitlyReportedFileAccesses, Processes = m_reports?.Processes, DumpFileDirectory = m_detouredProcess.DumpFileDirectory, DumpCreationException = m_detouredProcess.DumpCreationException, StandardInputException = standardInputException, MessageProcessingFailure = m_reports?.MessageProcessingFailure, ProcessStartTime = m_detouredProcess.StartTime, HasReadWriteToReadFileAccessRequest = m_reports?.HasReadWriteToReadFileAccessRequest ?? false, }; SetResult(result); }
private async Task OnProcessExitedAsync() { // Wait until all incoming report messages from the detoured process have been handled. await WaitUntilReportEof(m_detouredProcess.Killed); // Ensure no further modifications to the report m_reports?.Freeze(); // We can get extended accounting information (peak memory, etc. rolled up for the entire process tree) if this process was wrapped in a job. JobObject.AccountingInformation?jobAccountingInformation = null; JobObject jobObject = m_detouredProcess.GetJobObject(); if (jobObject != null) { var accountingInfo = jobObject.GetAccountingInformation(); // Only overwrite memory counters if <see cref="GetMemoryCountersSnapshot"/> did get triggered previously. This isn't the case if the // detours sandbox is used outside of BuildXL (currently only the scheduler calls this). The <see cref="JobObject.GetAccountingInformation"/> // function does populate memory counters for the process tree if possible, so don't overwrite them with empty aggregator values. if (m_peakWorkingSet.Count > 0 || m_workingSet.Count > 0 || m_peakCommitSize.Count > 0 || m_commitSize.Count > 0) { accountingInfo.MemoryCounters = Pips.ProcessMemoryCounters.CreateFromBytes( peakWorkingSet: Convert.ToUInt64(m_peakWorkingSet.Maximum), averageWorkingSet: Convert.ToUInt64(m_workingSet.Average), peakCommitSize: Convert.ToUInt64(m_peakCommitSize.Maximum), averageCommitSize: Convert.ToUInt64(m_commitSize.Average)); } jobAccountingInformation = accountingInfo; } ProcessTimes primaryProcessTimes = m_detouredProcess.GetTimesForPrimaryProcess(); IOException standardInputException = null; try { await m_standardInputTcs.Task; } catch (IOException ex) { standardInputException = ex; } // Construct result; note that the process is expected to have exited at this point, even if we decided to forcefully kill it // (this callback is always a result of the process handle being signaled). int exitCode = 0; if (m_reports?.MessageProcessingFailure != null) { exitCode = ExitCodes.MessageProcessingFailure; } else { Contract.Assert(m_detouredProcess.HasExited, "Detoured process has not been marked as exited"); exitCode = m_detouredProcess.GetExitCode(); } SandboxedProcessResult result = new SandboxedProcessResult { // If there is a message parsing failure, fail the pip. ExitCode = exitCode, Killed = m_detouredProcess.Killed, TimedOut = m_detouredProcess.TimedOut, HasDetoursInjectionFailures = m_detouredProcess.HasDetoursInjectionFailures, SurvivingChildProcesses = m_survivingChildProcesses?.Values.ToArray(), PrimaryProcessTimes = primaryProcessTimes, JobAccountingInformation = jobAccountingInformation, StandardOutput = m_output.Freeze(), StandardError = m_error.Freeze(), AllUnexpectedFileAccesses = m_reports?.FileUnexpectedAccesses, FileAccesses = m_reports?.FileAccesses, DetouringStatuses = m_reports?.ProcessDetoursStatuses, ExplicitlyReportedFileAccesses = m_reports?.ExplicitlyReportedFileAccesses, Processes = m_reports?.Processes, DumpFileDirectory = m_detouredProcess.DumpFileDirectory, DumpCreationException = m_detouredProcess.DumpCreationException, StandardInputException = standardInputException, MessageProcessingFailure = m_reports?.MessageProcessingFailure, ProcessStartTime = m_detouredProcess.StartTime, HasReadWriteToReadFileAccessRequest = m_reports?.HasReadWriteToReadFileAccessRequest ?? false, DiagnosticMessage = m_detouredProcess.Diagnostics }; SetResult(result); }