Пример #1
0
        /// <summary>
        /// Deserializes an instance of <see cref="SandboxedProcessResult"/>.
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        public static SandboxedProcessResult Deserialize(BuildXLReader reader)
        {
            int  exitCode = reader.ReadInt32();
            bool killed   = reader.ReadBoolean();
            bool timedOut = reader.ReadBoolean();
            bool hasDetoursInjectionFailures = reader.ReadBoolean();

            IReadOnlyList <ReportedProcess> allReportedProcesses    = reader.ReadReadOnlyList(r => ReportedProcess.Deserialize(r));
            IReadOnlyList <ReportedProcess> survivingChildProcesses = reader.ReadNullable(r => r.ReadReadOnlyList(r2 => allReportedProcesses[r2.ReadInt32()]));
            ProcessTimes primaryProcessTimes = reader.ReadNullable(r => ProcessTimes.Deserialize(r));

            JobObject.AccountingInformation?           jobAccountingInformation       = reader.ReadNullableStruct(r => JobObject.AccountingInformation.Deserialize(r));
            SandboxedProcessOutput                     standardOutput                 = reader.ReadNullable(r => SandboxedProcessOutput.Deserialize(r));
            SandboxedProcessOutput                     standardError                  = reader.ReadNullable(r => SandboxedProcessOutput.Deserialize(r));
            IReadOnlyList <ReportedFileAccess>         fileAccesses                   = reader.ReadNullable(r => r.ReadReadOnlyList(r2 => ReportedFileAccess.Deserialize(r2, allReportedProcesses, readPath: null)));
            IReadOnlyList <ReportedFileAccess>         explicitlyReportedFileAccesses = reader.ReadNullable(r => r.ReadReadOnlyList(r2 => ReportedFileAccess.Deserialize(r2, allReportedProcesses, readPath: null)));
            IReadOnlyList <ReportedFileAccess>         allUnexpectedFileAccesses      = reader.ReadNullable(r => r.ReadReadOnlyList(r2 => ReportedFileAccess.Deserialize(r2, allReportedProcesses, readPath: null)));
            IReadOnlyList <ReportedProcess>            processes         = reader.ReadNullable(r => r.ReadReadOnlyList(r2 => allReportedProcesses[r2.ReadInt32()]));
            IReadOnlyList <ProcessDetouringStatusData> detouringStatuses = reader.ReadNullable(r => r.ReadReadOnlyList(r2 => ProcessDetouringStatusData.Deserialize(r2)));
            string dumpFileDirectory                   = reader.ReadNullableString();
            string dumpCreationExceptionMessage        = reader.ReadNullableString();
            string standardInputExceptionMessage       = reader.ReadNullableString();
            int    numberOfPRocessLaunchRetries        = reader.ReadInt32();
            bool   hasReadWriteToReadFileAccessRequest = reader.ReadBoolean();
            string messageProcessingFailureMessage     = reader.ReadNullableString();
            long   processStartTime             = reader.ReadInt64();
            int    warningCount                 = reader.ReadInt32();
            long   detoursMaxHeapSize           = reader.ReadInt64();
            int    lastMessageCount             = reader.ReadInt32();
            bool   messageCountSemaphoreCreated = reader.ReadBoolean();

            return(new SandboxedProcessResult()
            {
                ExitCode = exitCode,
                Killed = killed,
                TimedOut = timedOut,
                HasDetoursInjectionFailures = hasDetoursInjectionFailures,
                SurvivingChildProcesses = survivingChildProcesses,
                PrimaryProcessTimes = primaryProcessTimes,
                JobAccountingInformation = jobAccountingInformation,
                StandardOutput = standardOutput,
                StandardError = standardError,
                FileAccesses = fileAccesses != null ? new HashSet <ReportedFileAccess>(fileAccesses) : null,
                ExplicitlyReportedFileAccesses = explicitlyReportedFileAccesses != null ? new HashSet <ReportedFileAccess>(explicitlyReportedFileAccesses) : null,
                AllUnexpectedFileAccesses = allUnexpectedFileAccesses != null ? new HashSet <ReportedFileAccess>(allUnexpectedFileAccesses) : null,
                Processes = processes,
                DetouringStatuses = detouringStatuses,
                DumpFileDirectory = dumpFileDirectory,
                DumpCreationException = dumpCreationExceptionMessage != null ? new Exception(dumpCreationExceptionMessage) : null,
                StandardInputException = standardInputExceptionMessage != null ? new Exception(standardInputExceptionMessage) : null,
                NumberOfProcessLaunchRetries = numberOfPRocessLaunchRetries,
                HasReadWriteToReadFileAccessRequest = hasReadWriteToReadFileAccessRequest,
                MessageProcessingFailure = messageProcessingFailureMessage != null ? new Failure <string>(messageProcessingFailureMessage) : null,
                ProcessStartTime = processStartTime,
                WarningCount = warningCount,
                DetoursMaxHeapSize = detoursMaxHeapSize,
                LastMessageCount = lastMessageCount,
                MessageCountSemaphoreCreated = messageCountSemaphoreCreated
            });
        }
Пример #2
0
 internal static SandboxedProcessPipExecutionResult RetryProcessDueToAzureWatsonExitCode(
     int numberOfProcessLaunchRetries,
     int exitCode,
     ProcessTimes primaryProcessTimes,
     JobObject.AccountingInformation?jobAccountingInformation,
     IReadOnlyList <ProcessDetouringStatusData> detouringStatuses,
     long sandboxPrepMs,
     long processSandboxedProcessResultMs,
     long processStartTime,
     long maxDetoursHeapSize,
     ContainerConfiguration containerConfiguration,
     Dictionary <string, int> pipProperties)
 {
     return(new SandboxedProcessPipExecutionResult(
                SandboxedProcessPipExecutionStatus.ShouldBeRetriedDueToAzureWatsonExitCode,
                observedFileAccesses: default(SortedReadOnlyArray <ObservedFileAccess, ObservedFileAccessExpandedPathComparer>),
                sharedDynamicDirectoryWriteAccesses: default(Dictionary <AbsolutePath, IReadOnlyCollection <AbsolutePath> >),
                encodedStandardError: null,
                encodedStandardOutput: null,
                numberOfWarnings: 0,
                unexpectedFileAccesses: null,
                primaryProcessTimes: primaryProcessTimes,
                jobAccountingInformation: jobAccountingInformation,
                numberOfProcessLaunchRetries: numberOfProcessLaunchRetries,
                exitCode: exitCode,
                sandboxPrepMs: sandboxPrepMs,
                processSandboxedProcessResultMs: processSandboxedProcessResultMs,
                processStartTime: processStartTime,
                allReportedFileAccesses: null,
                detouringStatuses: detouringStatuses,
                maxDetoursHeapSize: maxDetoursHeapSize,
                containerConfiguration: containerConfiguration,
                pipProperties: pipProperties));
 }
 internal static SandboxedProcessPipExecutionResult FailureButRetryAble(
     SandboxedProcessPipExecutionStatus status,
     RetryInfo retryInfo,
     long maxDetoursHeapSize          = 0,
     ProcessTimes primaryProcessTimes = null)
 {
     return(new SandboxedProcessPipExecutionResult(
                status,
                observedFileAccesses: default(SortedReadOnlyArray <ObservedFileAccess, ObservedFileAccessExpandedPathComparer>),
                sharedDynamicDirectoryWriteAccesses: null,
                encodedStandardError: null,
                encodedStandardOutput: null,
                numberOfWarnings: 0,
                unexpectedFileAccesses: null,
                primaryProcessTimes: primaryProcessTimes,
                jobAccountingInformation: null,
                exitCode: 0,
                sandboxPrepMs: 0,
                processSandboxedProcessResultMs: 0,
                processStartTime: 0L,
                allReportedFileAccesses: null,
                detouringStatuses: null,
                maxDetoursHeapSize: maxDetoursHeapSize,
                containerConfiguration: ContainerConfiguration.DisabledIsolation,
                pipProperties: null,
                timedOut: false,
                retryInfo: retryInfo,
                createdDirectories: null));
 }
        /// <nodoc />
        public SandboxedProcessPipExecutionResult(
            SandboxedProcessPipExecutionStatus status,
            SortedReadOnlyArray <ObservedFileAccess, ObservedFileAccessExpandedPathComparer> observedFileAccesses,
            IReadOnlyDictionary <AbsolutePath, IReadOnlyCollection <FileArtifactWithAttributes> > sharedDynamicDirectoryWriteAccesses,
            Tuple <AbsolutePath, Encoding> encodedStandardOutput,
            Tuple <AbsolutePath, Encoding> encodedStandardError,
            int numberOfWarnings,
            FileAccessReportingContext unexpectedFileAccesses,
            ProcessTimes primaryProcessTimes,
            JobObject.AccountingInformation?jobAccountingInformation,
            int exitCode,
            long sandboxPrepMs,
            long processSandboxedProcessResultMs,
            long processStartTime,
            IReadOnlyList <ReportedFileAccess> allReportedFileAccesses,
            IReadOnlyList <ProcessDetouringStatusData> detouringStatuses,
            long maxDetoursHeapSize,
            ContainerConfiguration containerConfiguration,
            Dictionary <string, int> pipProperties,
            bool timedOut,
            IReadOnlySet <AbsolutePath> createdDirectories,
            RetryInfo retryInfo = null)
        {
            Contract.Requires(!ProcessCompletedExecution(status) || observedFileAccesses.IsValid);
            Contract.Requires(!ProcessCompletedExecution(status) || unexpectedFileAccesses != null);
            Contract.Requires(!ProcessCompletedExecution(status) || primaryProcessTimes != null);
            Contract.Requires(encodedStandardOutput == null || (encodedStandardOutput.Item1.IsValid && encodedStandardOutput.Item2 != null));
            Contract.Requires(encodedStandardError == null || (encodedStandardError.Item1.IsValid && encodedStandardError.Item2 != null));
            Contract.Requires(numberOfWarnings >= 0);
            Contract.Requires(containerConfiguration != null);
            Contract.Requires(retryInfo == null || status != SandboxedProcessPipExecutionStatus.Succeeded);

            // Protect against invalid combinations of RetryLocation and RetryReason
            Contract.Requires(!retryInfo.CanBeRetriedInlineOrFalseIfNull() || retryInfo.RetryReason != RetryReason.ResourceExhaustion);
            Contract.Requires(!retryInfo.CanBeRetriedInlineOrFalseIfNull() || retryInfo.RetryReason != RetryReason.ProcessStartFailure);
            Contract.Requires(!retryInfo.CanBeRetriedInlineOrFalseIfNull() || retryInfo.RetryReason != RetryReason.TempDirectoryCleanupFailure);
            Contract.Requires(!retryInfo.CanBeRetriedInlineOrFalseIfNull() || retryInfo.RetryReason != RetryReason.StoppedWorker);

            Status = status;
            ObservedFileAccesses     = observedFileAccesses;
            UnexpectedFileAccesses   = unexpectedFileAccesses;
            EncodedStandardOutput    = encodedStandardOutput;
            EncodedStandardError     = encodedStandardError;
            NumberOfWarnings         = numberOfWarnings;
            PrimaryProcessTimes      = primaryProcessTimes;
            JobAccountingInformation = jobAccountingInformation;
            ExitCode      = exitCode;
            SandboxPrepMs = sandboxPrepMs;
            ProcessSandboxedProcessResultMs = processSandboxedProcessResultMs;
            ProcessStartTimeMs                  = processStartTime;
            AllReportedFileAccesses             = allReportedFileAccesses;
            DetouringStatuses                   = detouringStatuses;
            MaxDetoursHeapSizeInBytes           = maxDetoursHeapSize;
            SharedDynamicDirectoryWriteAccesses = sharedDynamicDirectoryWriteAccesses;
            ContainerConfiguration              = containerConfiguration;
            PipProperties      = pipProperties;
            TimedOut           = timedOut;
            RetryInfo          = retryInfo;
            CreatedDirectories = createdDirectories ?? CollectionUtilities.EmptySet <AbsolutePath>();
        }
Пример #5
0
        /// <nodoc />
        public SandboxedProcessPipExecutionResult(
            SandboxedProcessPipExecutionStatus status,
            SortedReadOnlyArray<ObservedFileAccess, ObservedFileAccessExpandedPathComparer> observedFileAccesses,
            IReadOnlyDictionary<AbsolutePath, IReadOnlyCollection<FileArtifactWithAttributes>> sharedDynamicDirectoryWriteAccesses,
            Tuple<AbsolutePath, Encoding> encodedStandardOutput,
            Tuple<AbsolutePath, Encoding> encodedStandardError,
            int numberOfWarnings,
            FileAccessReportingContext unexpectedFileAccesses,
            ProcessTimes primaryProcessTimes,
            JobObject.AccountingInformation? jobAccountingInformation,
            int numberOfProcessLaunchRetries,
            int exitCode,
            long sandboxPrepMs,
            long processSandboxedProcessResultMs,
            long processStartTime,
            IReadOnlyList<ReportedFileAccess> allReportedFileAccesses,
            IReadOnlyList<ProcessDetouringStatusData> detouringStatuses,
            long maxDetoursHeapSize,
            ContainerConfiguration containerConfiguration,
            Dictionary<string, int> pipProperties,
            bool timedOut,
            CancellationReason cancellationReason = CancellationReason.None)
        {
            Contract.Requires(
                (status == SandboxedProcessPipExecutionStatus.PreparationFailed ||
                status == SandboxedProcessPipExecutionStatus.ShouldBeRetriedDueToUserSpecifiedExitCode ||
                status == SandboxedProcessPipExecutionStatus.Canceled) ||
                observedFileAccesses.IsValid);
            Contract.Requires(
                (status == SandboxedProcessPipExecutionStatus.PreparationFailed || status == SandboxedProcessPipExecutionStatus.ShouldBeRetriedDueToUserSpecifiedExitCode ||
                status == SandboxedProcessPipExecutionStatus.Canceled) ||
                unexpectedFileAccesses != null);
            Contract.Requires((status == SandboxedProcessPipExecutionStatus.PreparationFailed || status == SandboxedProcessPipExecutionStatus.Canceled) || primaryProcessTimes != null);
            Contract.Requires(encodedStandardOutput == null || (encodedStandardOutput.Item1.IsValid && encodedStandardOutput.Item2 != null));
            Contract.Requires(encodedStandardError == null || (encodedStandardError.Item1.IsValid && encodedStandardError.Item2 != null));
            Contract.Requires(numberOfWarnings >= 0);
            Contract.Requires(containerConfiguration != null);

            Status = status;
            ObservedFileAccesses = observedFileAccesses;
            UnexpectedFileAccesses = unexpectedFileAccesses;
            EncodedStandardOutput = encodedStandardOutput;
            EncodedStandardError = encodedStandardError;
            NumberOfWarnings = numberOfWarnings;
            PrimaryProcessTimes = primaryProcessTimes;
            JobAccountingInformation = jobAccountingInformation;
            NumberOfProcessLaunchRetries = numberOfProcessLaunchRetries;
            ExitCode = exitCode;
            SandboxPrepMs = sandboxPrepMs;
            ProcessSandboxedProcessResultMs = processSandboxedProcessResultMs;
            ProcessStartTimeMs = processStartTime;
            AllReportedFileAccesses = allReportedFileAccesses;
            DetouringStatuses = detouringStatuses;
            MaxDetoursHeapSizeInBytes = maxDetoursHeapSize;
            SharedDynamicDirectoryWriteAccesses = sharedDynamicDirectoryWriteAccesses;
            ContainerConfiguration = containerConfiguration;
            PipProperties = pipProperties;
            TimedOut = timedOut;
            CancellationReason = cancellationReason;
        }
 internal static SandboxedProcessPipExecutionResult RetryProcessDueToUserSpecifiedExitCode(
     int exitCode,
     ProcessTimes primaryProcessTimes,
     JobObject.AccountingInformation?jobAccountingInformation,
     IReadOnlyList <ProcessDetouringStatusData> detouringStatuses,
     long sandboxPrepMs,
     long processSandboxedProcessResultMs,
     long processStartTime,
     long maxDetoursHeapSize,
     ContainerConfiguration containerConfiguration,
     Tuple <AbsolutePath, Encoding> encodedStandardError,
     Tuple <AbsolutePath, Encoding> encodedStandardOutput,
     Dictionary <string, int> pipProperties,
     IReadOnlyDictionary <AbsolutePath, IReadOnlyCollection <FileArtifactWithAttributes> > sharedDynamicDirectoryWriteAccesses,
     RetryInfo retryInfo = null)
 {
     return(new SandboxedProcessPipExecutionResult(
                SandboxedProcessPipExecutionStatus.ExecutionFailed,
                observedFileAccesses: default(SortedReadOnlyArray <ObservedFileAccess, ObservedFileAccessExpandedPathComparer>),
                sharedDynamicDirectoryWriteAccesses: sharedDynamicDirectoryWriteAccesses,
                encodedStandardError: encodedStandardError,
                encodedStandardOutput: encodedStandardOutput,
                numberOfWarnings: 0,
                unexpectedFileAccesses: null,
                primaryProcessTimes: primaryProcessTimes,
                jobAccountingInformation: jobAccountingInformation,
                exitCode: exitCode,
                sandboxPrepMs: sandboxPrepMs,
                processSandboxedProcessResultMs: processSandboxedProcessResultMs,
                processStartTime: processStartTime,
                allReportedFileAccesses: null,
                detouringStatuses: detouringStatuses,
                maxDetoursHeapSize: maxDetoursHeapSize,
                containerConfiguration: containerConfiguration,
                pipProperties: pipProperties,
                timedOut: false,
                retryInfo: retryInfo ?? RetryInfo.GetDefault(RetryReason.UserSpecifiedExitCode),
                createdDirectories: null));
 }
Пример #7
0
        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);
        }
Пример #8
0
        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);
        }