Question

I have the code following below that is for problem illustration only. Please ignore the part where CodeDom is used to compile the sources. Also in case you try it it leaves the "other process" executable running and consuming CPU time for no good.

The real problem is I start the thread, then abort the thread and see "Thread abort initiated" message and there's

A first chance exception of type 'System.Threading.ThreadAbortException' occurred in mscorlib.dll

message in the debugger output but neither catch nor finally blocks are invoked and there's no output from those blocks.

Of course because the extra threads created to handle the redirected output are not aborted the program hangs forever, but...

Why are catch and finally not invoked?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Diagnostics;
using Microsoft.CSharp;
using System.CodeDom.Compiler;

namespace ConsoleApplication
{
  class Program
  {
    static void Main(string[] args)
    {
      new Program().payload();
    }

    private void payload()
    {
      var otherExecutableName = "OtherProcess.exe";
      compileOtherProcessExecutable(otherExecutableName);
      var thread = new System.Threading.Thread(() => threadFunc(otherExecutableName));
      thread.Start();
      Thread.Sleep( 1000 );
      thread.Abort();
      Debug.WriteLine("Thread abort initiated");
    }

    private void threadFunc( String secondExecutableName )
    {
        Process process = null;
        try {
            process = new Process();
            {
                process.StartInfo.FileName = secondExecutableName;
                process.StartInfo.UseShellExecute = false;
                process.StartInfo.RedirectStandardOutput = true;
                process.StartInfo.RedirectStandardError = true;

                process.OutputDataReceived += new DataReceivedEventHandler(outputHandler);
                process.ErrorDataReceived += new DataReceivedEventHandler(outputHandler);

                process.Start();

                process.BeginOutputReadLine();
                process.BeginErrorReadLine();

                process.WaitForExit();
            }
        } catch( Exception e ) {
            Debug.WriteLine( "Catch block: " + e.Message );
        } finally {
            Debug.WriteLine( "Finally block" );
            if( process != null ) {
                process.Kill();
                Debug.WriteLine( "Process killed" );
            }
        }
    }

    static void compileOtherProcessExecutable(string filePath)
    {
        using (var compiler = new CSharpCodeProvider())
        {
            var parameters = new CompilerParameters(null, filePath, true);
            parameters.GenerateExecutable = true;
            var compResult = compiler.CompileAssemblyFromSource( parameters, otherProcessCode);
            var errs = compResult.Errors;
            if (errs.HasErrors)
            {
                var err = errs.Cast<CompilerError>().First();
                throw new InvalidOperationException(String.Format(
                    "Compilation failed. Line {0}: {1}", err.Line, err.ErrorText));
            }
        }
    }

    private void outputHandler(object process, DataReceivedEventArgs output)
    {
    }

    static readonly String otherProcessCode =
        @"class Program {
            public static void Main(string[] args)
            {
                while( true ) {
                }
            }
        }";
  }
}
Was it helpful?

Solution

The problem is the WaitForExit call. This managed call will eventually bottom out in a native frame. When an Abort call occurs while the thread is in native code nothing will actually happen until the thread returns to managed code. In this case the thread is waiting for the process to finish and hence won't actually return until you physically kill the process

Note: Even if the exception was thrown the catch block won't actually catch it. The exception will be rethrown at the end of the block. You need to catch it and call the ResetAbort method

OTHER TIPS

You can read here:

ThreadAbortException is a special exception that can be caught, but it will automatically be raised again at the end of the catch block. When this exception is raised, the runtime executes all the finally blocks before ending the thread.

But also, I think you should wrap the whole method inside the try.

Or, do you think your external process could have finished before the call to abort and hence the method with the catch, the one called threadFunc, is no longer executing?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top