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. 


Consider the simple example:

using System;

class Foo
static void Main(string[] args)
AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit);

static void CurrentDomain_ProcessExit(object sender, EventArgs e)
Console.WriteLine(“Process is exiting!”);

Normally, this would print:

<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).

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 (7)

  1. Anders Dalvander says:

    Shouldn’t the Main method be something like this instead:

    static void Main(string[] args)


       AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit);




    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.

  2. Alois Kraus says:

    Hi Mike,

    more infos about abnormal and cooperatice application shutdown with the CLR can be found here:


     Alois Kraus

  3. 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.

  4. Antosha says:

    The example is not just contrived; it actually does not prove your point. If you kill the process on Console.ReadLine, the CurrentDomain.ProcessExit is not set *yet*.

  5. Antosha – you’re toally right. A silly mistake on my part. I’ve corrected it and reverified. Thanks.

  6. sam says:


    I got another problem on AppDomain.ProcessExit.

    According to msdn,there is only 3 sec limit when ProcessExit.

    ref url>>

    How can we extend the time limit to more than 3 sec?



  7. Sam –

    I looked at the english (en-us) version of the URL instead of (zh-tw).

    I see it says:

    The total execution time of all ProcessExit event handlers is limited, just as the total execution time of all finalizers is limited at process shutdown. The default is three seconds, which can be overridden by an unmanaged host.

    Key sentence there is "which can be overridden by an unmanaged host", which means using the hosting API (defined in mscoree.idl).

    I’m not sure which hosting API. However, do you really want to rely on the ProcessExit event since it’s not reliably called?