¿Por qué ExecuteCodeWithGuaranteedCleanup no funciona?

Estaba tratando de “medir” la profundidad de la stack. ¿Por qué el siguiente progtwig no imprime nada?

class Program { private static int Depth = 0; static void A(object o) { Depth++; A(o); } static void B(object o, bool e) { Console.WriteLine(Depth); } static void Main(string[] args) { RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(A, B, null); } } 

Algunas respuestas simplemente incluyen una cita de MSDN, como “A partir de .NET Framework versión 2.0, un bloque Try-catchflow no puede detectar un objeto StackOverflowException y el proceso correspondiente finaliza de forma predeterminada”. Créeme, a veces (cuando hay suficiente espacio en la stack) puede ser algo, lo siguiente imprime un número:

 class Program { private static int depth = 0; static void A(object o) { depth++; if (Environment.StackTrace.Length > 8000) throw new StackOverflowException("Catch me if you can."); A(o); } static void B(object o, bool e) { Console.WriteLine(depth); } static void Main(string[] args) { RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(A, B, null); } } 

Si desea capturarlo, cárguelo en otro proceso (que devuelve la llamada al suyo a través de una comunicación remota) y deje que el código malicioso se ejecute allí. El otro proceso puede finalizar, y podría obtener una SOE ordenada que sobresalga del extremo de la tubería de su lado, sin los efectos adversos de la excepción bastante inconveniente.

Tenga en cuenta que un AppDomain separado en el mismo proceso no lo cortará.

Si desea obtener el seguimiento de la stack de una excepción, el siguiente código le hará mucha justicia:

  class Program { static void Main(string[] args) { try { Recurse(0); } catch (Exception ex) { StackTrace st = new StackTrace(ex); // Go wild. Console.WriteLine(st.FrameCount); } Console.ReadLine(); } static void Recurse(int counter) { if (counter >= 100) throw new Exception(); Recurse(++counter); } } 

Con respecto a su edición, no creo que el código de usuario que lanza una excepción StackOverflowException sea el mismo que el CLR que lo lanzó.

Hay un poco de discusión al respecto aquí .

El comentario de Jeffrey (Richter, autor de Applied Microsoft® .NET Framework Programming ) se aplica a los desbordamientos de stack reales, es decir, a los desbordamientos de stack que se producen si su código contiene una recursión infinita, algo como:

void MyMethod () {MyMethod (); }

Si lanza la StackOverflowException usted mismo, se manejará como cualquier otra excepción, y el comentario de Jeffrey no se aplica.

Además, el comentario de Jeffrey dice: “si se produce el desbordamiento de stack DENTRO DEL CLR EN SÍ MISMO …”. Por lo tanto, si la máquina virtual .NET puede detectar el desbordamiento de la stack “limpiamente”, es decir, sin ejecutar ITSELF en un desbordamiento de stack, debería obtener una StackOverflowException y su captura y finalmente los bloques deberían ejecutarse como de costumbre. Pero, en el caso trágico en el que la VM ITSELF se topa con un desbordamiento de stack, no tendrá tanta suerte: la VM no propagará una StackOverflowException (sino que se bloqueará de alguna otra forma extraña) y su captura y finalmente los bloques no se ejecutarán .

La moral es: tenga cuidado con la recursión infinita porque no tiene una garantía del 100% de que la máquina virtual detectará y señalará de forma limpia.

Bruno

Aclaró quién era “Jeffrey” ya que el OP citaba ese libro.

Según MSDN :

En versiones anteriores de .NET Framework, su aplicación podría detectar un objeto StackOverflowException (por ejemplo, para recuperarse de una recursión ilimitada). Sin embargo, actualmente no se recomienda esa práctica porque se requiere un código adicional significativo para capturar de manera confiable una excepción de desbordamiento de stack y continuar la ejecución del progtwig.

A partir de .NET Framework versión 2.0, un bloque try-catch no puede capturar un objeto StackOverflowException y el proceso correspondiente finaliza de forma predeterminada. En consecuencia, se recomienda a los usuarios que escriban su código para detectar y evitar un desbordamiento de stack. Por ejemplo, si su aplicación depende de la recursión, use un contador o una condición de estado para terminar el ciclo recursivo. Tenga en cuenta que una aplicación que aloja el tiempo de ejecución de lenguaje común (CLR) puede especificar que CLR descargue el dominio de la aplicación donde se produce la excepción de desbordamiento de stack y deje que el proceso correspondiente continúe. Para obtener más información, consulte Interfaz de ICLRPolicyManager y Alojamiento del Common Language Runtime.

Debido a este hecho, no creo que pueda hacer lo que quiere hacer ya que la `StackOverflowException terminará el proceso.

A partir de .NET Framework versión 2.0, un bloque try-catch no puede capturar un objeto StackOverflowException y el proceso correspondiente finaliza de forma predeterminada