C# Expressions - FatalExecutionEngineError
Asked Answered
F

1

9

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:

FatalExecutionEngineError

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 an Expression.Call() to Method A again. So after I compile the Lambda for the ExpressionTree, the generated Delegate (let's call it Method 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. When Method 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);
        }
    }
}
Faerie answered 25/2, 2015 at 15:3 Comment(5)
Wow! It works/explodes! :-)Unobtrusive
I get the same thing when using VS2012 or VS2010, but only when using the steps you describe. It only blows up if I step into the @delegate.DynamicInvoke, then continue stepping over (not letting it run).Ody
Since it runs fine when not debugging, I would guess it is a problem with the debugger.Ody
@Puer VS 2013 Update 4, tested both 32 and 64 bit appUnobtrusive
I have faced the same problem. Ignored and continued the rest of my work as it works when we don't step through it. If only .Net 4.5 (or lesser) installed this won't happen. Problem starts from .Net 4.5.1 is what I found.Fargone
D
6

Your repro code is excellent, this bombs reliably. It is highly specific to the v4 debugging engine for 32-bit code, it does not occur for the v2 engine or the 64-bit debugger engine. Both the old and the new v4 engine have this problem.

I don't see much of anything recognizable when I debug the debugger, the code that fails is located in mscorlib.dll with an explicit throw. Nothing familiar, I see a few hints to an unmanaged class named ILTree. Not something that Microsoft shares with us, it is not present in the Reference Source, SSCLI20 or CoreCLR source code.

This is something for Microsoft to worry about. Report the bug through connect.microsoft.com. A link to this SO question should suffice to document it. Let me know if you don't want to take the time to do it and I'll take care of it.

Meanwhile you do have a decent workaround to keep going, just let your program run in 64-bit mode by removing the jitter forcing. Project + Properties, Build tab, untick the "Prefer 32-bit" option and select AnyCPU for the Platform target. Please follow up when you hear back from Microsoft.

Draughtsman answered 25/2, 2015 at 16:58 Comment(1)
Thank you so much Hans. Everytime I stand dumbfounded before an issue, you suddenly come charging in with such detailed analysis :) I have submitted the bug report here: connect.microsoft.com/VisualStudio/feedback/details/1148770Faerie

© 2022 - 2024 — McMap. All rights reserved.