Of course no software is ever released without bugs, and the .Net Framework is no exception.  With .Net 4.6, Microsoft has moved to using a new JIT compiler called RyuJIT that is specifically designed for use with 64-bit systems.  However, Nick Craver at StackOverflow has found that this new JIT compiler has a significant bug in it’s Tail Call Optimization that means the parameters you pass into a method might not be the same after compilation.

There is an issue in the .Net 4.6 RTM RyuJIT implementation that incorrectly hooks up parameters during some tail call optimizations. The net result of this is that tail call methods can get the wrong parameters passed.  — GitHub Post

There are several factors that make this bug particularly troublesome, including these from Nick Carver’s blog.

  • It only happens with optimizations enabled. For most developers and projects, that’s not in DEBUG and won’t show locally.
    • That means you’ll only see this in RELEASE, which for most people is only production.
  • Attaching a debugger alters the behavior. This almost always hides the issue.
  • Adding a Debug.WriteLine() will often fix the issue because of the tail change.
  • It won’t reproduce in certain scenarios (e.g. we can’t repro this in a console application or VS hosting, only IIS).
  • Given the nature of the bug, as far as we can tell, it can equally affect any framework library as well.
  • It can happen in a NuGet library (most of which are RELEASE); the issue may not be in your code at all.
  • While Microsoft apparently has a fix for this already internally, there is some question as to how soon that fix will be made available to .Net 4.6 users.

Since publicly posting this bug, Microsoft has since submitted code to GitHub for a fix but there is still some question about when that fix will be pushed out to users.  In the meantime, the recommended workaround is to disable the RyuJIT compiler and go back to the older .Net JIT compiler.  You can do this by setting a value in the registry as shown below.

HKEY_LOCAL_MACHINESOFTWAREMicrosoft.NETFrameworkuseLegacyJit =  DWORD (1)