Today I was debugging some code of mine that builds a few ExpressionTrees, compiles them to callable Delegates and calls them afterwards if required. While doing this I encountered a FatalExecutionEngineError
stepping through the code:
At first I was a little bit shocked since I had no idea what could have been possibly wrong with my Expressions, they looked all fine. Then I found out that this only happens in the following situation:
Method A
is a static method that is called and generates the ExpressionTree, which can possibly contain anExpression.Call()
toMethod A
again. So after I compile the Lambda for the ExpressionTree, the generated Delegate (let's call itMethod B
) may possible cause recursion if I call it from within this method... (Method A
->[Generated]Method B
->Method A
)....which is totally possible in my scenario. As described above I was debugging this piece of code, so I set a breakpoint in
Method A
.The first time
Method A
is called by the regular code, the breakpoint hits as usual. WhenMethod B
is called, the breakpoint hits a second time, still everything is ok.But as soon as I leave the second call with the debugger by stepping over the last line, the
FatalExecutionEngineError
occurs.
If I run the code without debugging, or do NOT step into the recursive call to Method A
, OR if I do NOT step over the last line of the method, the problem does not occur and my Expression code is executed as expected.
I can't determine if this is an error in the VS-Debugger or the .NET Framework, or if I do something horribly, horribly wrong that only comes up when debugging the relevant lines.
Here is a very bare example code you can run out of the box. I am using Visual Studio 2013 Prof Update 4 and .NET 4.5.1. Just set a breakpoint in DoSomething()
and try to step through to the end - if you can ;)
Can anyone confirm a bug, or is my Expression ill-formed?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace ExpressionProblem
{
public class MainClass
{
public static void DoSomething(bool stop)
{
var method = typeof(MainClass).GetMethod(
"DoSomething",
BindingFlags.Public | BindingFlags.Static,
Type.DefaultBinder,
new Type[] { typeof(bool) },
null);
var expParam = Expression.Parameter(typeof(bool), "stop");
var expCall = Expression.Call(null, method, expParam);
var lambda = Expression.Lambda(expCall, expParam);
var @delegate = lambda.Compile();
if(!stop)
{
@delegate.DynamicInvoke(true);
}
}
public static void Main(string[] args)
{
DoSomething(false);
}
}
}
@delegate.DynamicInvoke
, then continue stepping over (not letting it run). – Ody