Partager via


AppDomain.ProcessExit is not guaranteed to be called

The AppDomain.ProcessExit is not guaranteed to be called. It's pretty resilient and will deal with common things you may cause from low-trust IL (exceptions, out-of-memory, etc), but there are some things (like rude process shutdown), that an inprocess event can never be resilient against. 

Demo:

Consider the simple example:

 
using System;

class Foo
{
    static void Main(string[] args)
    {
        AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit); 
        Console.WriteLine("start");
        Console.ReadLine();
    }

    static void CurrentDomain_ProcessExit(object sender, EventArgs e)
    {
        Console.WriteLine("Process is exiting!");
    }
}

Normally, this would print:

 start
 <whatever text you enter at the readline> 
Process is exiting!

However, if while the process is stopped at ReadLine, we use task manager to rudely kill it, then the ProcessExit event will not run. Try for yourself!
(Update[12/1/06]: kudos to Antosha for pointing out that if the ProcessExit event is hooked after the ReadLine, it proves nothing. I've updated the example and reverified that it indeed doesn't run).

Why?
The callback is invoked from within the process. If the process rudely exits, the callback would not be invoked.  Common sources for rudely exiting include:
1. Killed externally via TaskManager or kernel32!TerminateProcess.
2. Stackoverflow handler consumes past the guard page.

The ProcessExit event is like telling somebody "please telephone me that your about to die". If death comes quickly enough, they may not get the message out.

Security Implications?
Don't have a security model that requires that the ProcessExit event be run on shutdown.

Compare to Debugger's Exit Process event:
In contrast, the Debugger's exit process event (via ICorDebugManagedCallback::ExitProcess) is reliable because it's in a separate process and directly wired to waiting on the process handle of the debuggee. (Process handles are signaled when the process exits).  This means a robust debugger can always expect the Exit Process event (as discussed on the forum here), but should not rely on any other event coming.

Comments

  • Anonymous
    November 26, 2006
    Shouldn't the Main method be something like this instead: static void Main(string[] args) {    AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit);    Console.WriteLine("start");    Console.ReadLine(); } It still doesn't help against kernel32!TerminateProcess, but placing the code at the end of the Main method seems like a strange and cumbersome way to call Console.WriteLine indirectly.

  • Anonymous
    November 27, 2006
    Hi Mike, more infos about abnormal and cooperatice application shutdown with the CLR can be found here: http://geekswithblogs.net/akraus1/archive/2006/10/30/95435.aspx Yours,  Alois Kraus

  • Anonymous
    November 27, 2006
    Anders - You're right that my example is contrived. It's trying to illustrate the limitations of ProcessExit, not find the most efficient way to call Console.WriteLine. Putting the callback at the start would be more natural. Alois - thanks for the link.

  • Anonymous
    November 30, 2006
    The comment has been removed

  • Anonymous
    December 01, 2006
    Antosha - you're toally right. A silly mistake on my part. I've corrected it and reverified. Thanks.

  • Anonymous
    December 28, 2006
    Hi I got another problem on AppDomain.ProcessExit. According to msdn,there is only 3 sec limit when ProcessExit. ref url>>http://msdn2.microsoft.com/zh-tw/library/system.appdomain.processexit(VS.80).aspx How can we extend the time limit to more than 3 sec? thx sam

  • Anonymous
    December 29, 2006
    The comment has been removed