Beispiel #1
0
        public ProcessTreeContext(Guid payloadGuid, SafeHandle reportPipe, ArraySegment <byte> payload, string dllNameX64, string dllNameX86, LoggingContext loggingContext)
        {
            // We cannot create this object in a wow64 process
            Contract.Assume(
                !ProcessUtilities.IsWow64Process(),
                "ProcessTreeContext:ctor - Cannot run injection server in a wow64 32 bit process");
            SafeFileHandle childHandle = null;

            m_loggingContext = loggingContext;

            // This object will be the server for the tree. CreateSourceFile the pipe server.
            try
            {
                SafeFileHandle injectorHandle;

                // Create a pipe for the requests
                Pipes.CreateInheritablePipe(Pipes.PipeInheritance.InheritWrite, Pipes.PipeFlags.ReadSideAsync, out injectorHandle, out childHandle);

                // Create the injector. This will duplicate the handles.
                Injector = ProcessUtilities.CreateProcessInjector(payloadGuid, childHandle, reportPipe, dllNameX86, dllNameX64, payload);

                // Create the request reader. We don't start listening until requested
                var injectionRequestFile = AsyncFileFactory.CreateAsyncFile(
                    injectorHandle,
                    FileDesiredAccess.GenericRead,
                    ownsHandle: true,
                    kind: FileKind.Pipe);
                m_injectionRequestReader = new AsyncPipeReader(injectionRequestFile, InjectCallback, Encoding.Unicode, BufferSize);
            }
            catch (Exception exception)
            {
                if (Injector != null)
                {
                    Injector.Dispose();
                    Injector = null;
                }

                if (m_injectionRequestReader != null)
                {
                    m_injectionRequestReader.Dispose();
                    m_injectionRequestReader = null;
                }

                throw new BuildXLException("Process Tree Context injector could not be created", exception);
            }
            finally
            {
                // Release memory. Since the child handle is duplicated, it can be released

                if (childHandle != null && !childHandle.IsInvalid)
                {
                    childHandle.Dispose();
                }
            }
        }
Beispiel #2
0
        private async Task WaitUntilReportEof(bool cancel)
        {
            using (await m_reportReaderSemaphore.AcquireAsync())
            {
                if (m_reportReader != null)
                {
                    if (!cancel)
                    {
                        await m_reportReader.WaitUntilEofAsync();
                    }

                    m_reportReader.Dispose();
                    m_reportReader = null;
                }
            }
        }
Beispiel #3
0
        public void Dispose()
        {
            // We dispose the injector first since it must have a write-handle to the pipe (to give to children).
            // EOF can't be reached until all writable handles are closed.
            // Requests after injector-dispose turn into no-ops (synchronized with a lock), and so the caller should take care to call Stop()
            // only after all processes have exited.
            if (Injector != null)
            {
                PrepareToStop();
            }

            if (m_injectionRequestReader != null)
            {
                m_injectionRequestReader.Dispose();
                m_injectionRequestReader = null;
            }
        }
Beispiel #4
0
        public void Start()
        {
            Contract.Assume(!m_processStarted);

            Encoding        reportEncoding  = Encoding.Unicode;
            SafeFileHandle  childHandle     = null;
            DetouredProcess detouredProcess = m_detouredProcess;

            using (m_reportReaderSemaphore.AcquireSemaphore())
            {
                SafeFileHandle reportHandle;

                try
                {
                    Pipes.CreateInheritablePipe(
                        Pipes.PipeInheritance.InheritWrite,
                        Pipes.PipeFlags.ReadSideAsync,
                        readHandle: out reportHandle,
                        writeHandle: out childHandle);

                    var setup =
                        new FileAccessSetup
                    {
                        ReportPath = "#" + childHandle.DangerousGetHandle().ToInt64(),
                        DllNameX64 = s_binaryPaths.DllNameX64,
                        DllNameX86 = s_binaryPaths.DllNameX86,
                    };

                    bool debugFlagsMatch = true;
                    ArraySegment <byte> manifestBytes = new ArraySegment <byte>();
                    if (m_fileAccessManifest != null)
                    {
                        manifestBytes = m_fileAccessManifest.GetPayloadBytes(setup, FileAccessManifestStream, m_timeoutMins, ref debugFlagsMatch);
                    }

                    if (!debugFlagsMatch)
                    {
                        throw new BuildXLException("Mismatching build type for BuildXL and DetoursServices.dll.");
                    }

                    m_standardInputTcs = TaskSourceSlim.Create <bool>();
                    detouredProcess.Start(
                        s_payloadGuid,
                        manifestBytes,
                        childHandle,
                        s_binaryPaths.DllNameX64,
                        s_binaryPaths.DllNameX86);

                    // At this point, we believe calling 'kill' will result in an eventual callback for job teardown.
                    // This knowledge is significant for ensuring correct cleanup if we did vs. did not start a process;
                    // if started, we expect teardown to happen eventually and clean everything up.
                    m_processStarted = true;

                    ProcessId = detouredProcess.GetProcessId();
                    m_processIdListener?.Invoke(ProcessId);
                }
                finally
                {
                    // release memory
                    m_fileAccessManifest = null;

                    // Note that in the success path, childHandle should already be closed (by Start).
                    if (childHandle != null && !childHandle.IsInvalid)
                    {
                        childHandle.Dispose();
                    }
                }

                var reportFile = AsyncFileFactory.CreateAsyncFile(
                    reportHandle,
                    FileDesiredAccess.GenericRead,
                    ownsHandle: true,
                    kind: FileKind.Pipe);
                StreamDataReceived reportLineReceivedCallback = m_reports == null ? (StreamDataReceived)null : ReportLineReceived;
                m_reportReader = new AsyncPipeReader(reportFile, reportLineReceivedCallback, reportEncoding, m_bufferSize);
                m_reportReader.BeginReadLine();
            }

            // don't wait, we want feeding in of standard input to happen asynchronously
            Analysis.IgnoreResult(FeedStandardInputAsync(detouredProcess, m_standardInputReader, m_standardInputTcs));
        }