Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.NET 6 crashes on a macOS 12.x virtual machine on Apple Silicon (arm64) #64103

Closed
jgiannuzzi opened this issue Jan 21, 2022 · 4 comments
Closed

Comments

@jgiannuzzi
Copy link
Contributor

jgiannuzzi commented Jan 21, 2022

Description

.NET 6 crashes when trying to run it in a macOS 12.x virtual machine on Apple Silicon (arm64). It works fine in a virtual machine on Intel (x64), or when running directly on the host.

Reproduction Steps

  1. Create a macOS virtual machine on Apple Silicon (MacVM is an open source project using Apple's Virtualization framework that can be used)
  2. Install .NET 6 runtime or SDK in the virtual machine
  3. Try to run e.g. dotnet --info and observe the crash

Expected behavior

.NET 6 works as well in a virtual machine as it does on the host (aka it does not crash).

Actual behavior

$ dotnet --info
Unhandled exception. System.TypeInitializationException: The type initializer for 'Microsoft.DotNet.Cli.Utils.Reporter' threw an exception.
 ---> System.TypeInitializationException: The type initializer for 'System.ConsolePal' threw an exception.
 ---> System.OutOfMemoryException: Array dimensions exceeded supported range.
   at System.ConsolePal..cctor()
   --- End of inner exception stack trace ---
   at System.Console.get_ForegroundColor()
   at Microsoft.DotNet.Cli.Utils.AnsiConsole..ctor(TextWriter writer)
   at Microsoft.DotNet.Cli.Utils.Reporter.Reset()
   at Microsoft.DotNet.Cli.Utils.Reporter..cctor()
   --- End of inner exception stack trace ---
   at Microsoft.DotNet.Cli.Utils.Reporter.get_Error()
   at Microsoft.DotNet.Cli.Program.Main(String[] args)
Abort trap: 6

Regression?

No response

Known Workarounds

  • Running the x64 version of .NET under Rosetta 2 emulation works fine.
  • Setting the environment variable COMPlus_ReadyToRun to 0 allows to run without crashing.

Configuration

.NET 6.0.1
macOS 12.0.1
ARM64
Virtual Machine

Other information

The issue comes from the fact that ReadyToRun is broken in .NET 6 on Apple Silicon because of a memory protection mishandling issue, resulting in the JIT version of the assemblies being used instead. This memory protection mishandling issue does not happen when running in a virtual machine, which does result in the ReadyToRun section of assemblies to be loaded successfully.
Unfortunately, there is a second bug in the way variadic function arguments are passed on Apple Silicon, but this only gets triggered in ReadyToRun code, not in JIT code. It happens when a new object array gets created: JIT code will use JIT_NewMDArrNonVarArg, but ReadyToRun code will use JIT_NewMDArr, passing variadic arguments in registers instead of on the stack, in contradiction to Apple's arm64 ABI guidelines. This results in the crash above.
Needless to say, creating new object arrays is a pretty common operation in the .NET runtime 😅

A big side effect of this bug is that load times of .NET on Apple Silicon are slower than they should be (when running on the host of course), as only JIT version of the assemblies are used. This seems to have always been broken (since support for Apple Silicon was added to .NET).

After quite a bit of research in the background during these past 2 months, I have come up with a fix for these 2 issues.
Whilst rebasing on main, I have noticed that they got fixed independently in #61938 for the memory protection mishandling issue, and #62855 for the new object array creation.
However those changes are impacting a much wider area of the runtime. I would thus advocate for backporting only the relevant changes to .NET 6, as it is the LTS release. Given the focus of that release on performance, and given that ReadyToRun has always been broken on Apple Silicon, I think that fixing .NET 6 would be the way to go, instead of waiting until .NET 7 is released.

I have created #64104 to address this issue.

@dotnet-issue-labeler dotnet-issue-labeler bot added the untriaged New issue has not been triaged by the area owner label Jan 21, 2022
@dotnet-issue-labeler
Copy link

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Jan 21, 2022
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Feb 7, 2022
@jgiannuzzi
Copy link
Contributor Author

Update: a workaround to avoid .NET 6 crashing in a macOS arm64 VM is to set the environment variable COMPlus_ReadyToRun to 0, e.g.

$ export COMPlus_ReadyToRun=0
$ dotnet --info
...

@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Apr 1, 2022
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Apr 13, 2022
@janvorli
Copy link
Member

@jgiannuzzi with the fix being in 6.0, can this issue be closed or is there still some remaining problem?

@jgiannuzzi
Copy link
Contributor Author

jgiannuzzi commented Jun 15, 2022

with the fix being in 6.0, can this issue be closed or is there still some remaining problem?

@janvorli I can confirm that the problem is fully solved since Runtime 6.0.5 / SDK 6.0.300.

@ghost ghost removed the untriaged New issue has not been triaged by the area owner label Jun 15, 2022
@ghost ghost locked as resolved and limited conversation to collaborators Jul 16, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants