Bueno, no sé si esto un error o simplemente un caso raro borde realmente RCE en el que no fueron diseñados para manejar.
Así que aquí está el código pertinente.
private static IEnumerable<int> Iterate()
{
RuntimeHelpers.PrepareConstrainedRegions();
try { cerWorked = false; yield return 5; }
finally { StackOverflow(); }
}
Cuando esto se compila e intentamos descompilarlo en C# con Reflector obtenemos esto.
private static IEnumerable<int> Iterate()
{
RuntimeHelpers.PrepareConstrainedRegions();
cerWorked = false;
yield return 5;
}
¡Ahora espere un segundo! El reflector ha estropeado todo esto. Así es como se ve realmente el IL.
.method private hidebysig static class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> Iterate() cil managed
{
.maxstack 2
.locals init (
[0] class Sandbox.Program/<Iterate>d__1 d__,
[1] class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> enumerable)
L_0000: ldc.i4.s -2
L_0002: newobj instance void Sandbox.Program/<Iterate>d__1::.ctor(int32)
L_0007: stloc.0
L_0008: ldloc.0
L_0009: stloc.1
L_000a: br.s L_000c
L_000c: ldloc.1
L_000d: ret
}
anuncio de que no es, de hecho, no hay ninguna llamada a PrepareConstrainedRegions
pesar de lo que dice el reflector. Entonces, ¿dónde está al acecho? Bueno, está justo allí en el IEnumerator
IEnumerator
método auto generado MoveNext
. Esta vez, Reflector lo hace bien.
private bool MoveNext()
{
try
{
switch (this.<>1__state)
{
case 0:
this.<>1__state = -1;
RuntimeHelpers.PrepareConstrainedRegions();
this.<>1__state = 1;
Program.cerWorked = false;
this.<>2__current = 5;
this.<>1__state = 2;
return true;
case 2:
this.<>1__state = 1;
this.<>m__Finally2();
break;
}
return false;
}
fault
{
this.System.IDisposable.Dispose();
}
}
Y de dónde vino esa llamada a StackOverflow
mueven misteriosamente? Justo dentro del método m_Finally2()
.
private void <>m__Finally2()
{
this.<>1__state = -1;
Program.StackOverflow();
}
Así que vamos a examinar esto un poco más de cerca. Ahora tenemos nuestra llamada PrepareConstainedRegions
dentro de un bloque try
en lugar de afuera donde debería estar. Y nuestra llamada StackOverflow
se ha movido de un bloque finally
a un bloque try
.
De acuerdo con documentationPrepareConstrainedRegions
debe preceder inmediatamente al bloque try
. Entonces, la suposición es que es ineficaz si se coloca en otro lugar.
Pero, incluso si el compilador de C# obtuviera esa parte correcta, las cosas seguirían estando dañadas porque los bloques try
no están restringidos. Solo están los bloques catch
, finally
y fault
. ¿Y adivina qué? ¡Esa llamada StackOverflow
se movió de un bloque finally
a un bloque try
!
Por lo que vale, parece ser la primera persona en notar esto ... al menos hasta donde pude ver en Google para otras referencias de la misma. –
Encontré este https://vmccontroller.svn.codeplex.com/svn/VmcController/VmcServices/DetectOpenFiles.cs fragmento de código en el que el confiado autor no va a obtener el CER que cree que está obteniendo. –
@Brian: Lol, agradable. Creo que es algo que la mayoría de la gente no usa muy a menudo, y los que probablemente ya lo saben intuitivamente, sin haber pensado en ello. Solo pienso, sin embargo. – Mehrdad