Tail Call bug Discovered in .NET 4.6

Tail Call bug Discovered in .NET 4.6

If you have begun using Visual Studio .NET 2015 you might want to hold off.  There is a serious bug that was discovered in .NET Framework 4.6 64 Bit optimizer that affects the last parameter that is placed in the tail call of functions.  This bug is simply being referred to the tail call bug (https://github.com/dotnet/coreclr/issues/1296).

To understand what this bug is you need to know a few things about tail calls and how compilers work in general.  First we will cover what a tail call is.  When you write a function in any modern language, may times you can have your return value be a return value from other function.  An example is demonstrated below:

function foo(data)
{
a(data);
    return b(data);
}

In the above example, the function foo() calls two functions, a() and b().  However the value from the function call b() is returned from foo().  This means that the call to b() is consider to be the tail call.  Your function can have multiple tail calls as demonstrated below:

function bar(data)
{
    if (a(data))
        return b(data);

    return c(data);
}

In this example, b() and c() are tail calls but a() is not.  You can read up more on tail calls here: https://en.wikipedia.org/wiki/Tail_call

The next topic to cover is code optimization.  When you compile your programs in most modern languages it will analyze your code and attempt to see if there is anything that can be substituted with a simpler set of instructions.  Please consider the following:

int a = 1 + (2 * 8);

An optimizer will see this and replace it with the following line before it creates the output assembly:

int a = 17;

As you can see that the final result of the variable a would be exactly the same but the code in the later example would execute faster.  For the case of the bug that is happening with .NET is affecting the optimization related to the last parameter of the tail call.  What is interesting about this bug is originating in the new RyuJIT which is supposed to affect 64 Bit versions of assemblies (http://blogs.msdn.com/b/dotnet/archive/2013/09/30/ryujit-the-next-generation-jit-compiler.aspx).

So now the question is what to do?

Well you can wait for this bug to be fixed.  Microsoft is working on a fix (https://github.com/dotnet/coreclr/pull/1298) but there is no word yet on when this will be released.

You can also disable the RyuJIT optimization by updating your registry: Under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft.NETFramework add a useLegacyJit DWORD with a value of 1.  After Microsoft does release the patch for this bug you should change the value back to 0.

Source: http://nickcraver.com/blog/2015/07/27/why-you-should-wait-on-dotnet-46/

Update (7/30/2015 @ 10:18 AM EST): 

The bug has been fixed and the patch has been made but it won’t be available into the next Windows Update.  No word yet on when this will be.  Rich Lander, who works on the Microsoft Common Language Runtime team, posted this:

rich_lander1

About the author
Michael Battaglia

Michael is a senior programmer for Multi Data Services in NY. Coding not just his day job, it is his passion.