runtime: Crash on using Expression.Compile() in a release mode (iOS).

Description

Please see following project to reproduce this issue: https://github.com/JaneySprings/MauiReflectionBug Same code works perfectly in Xamarin.Forms (iOS release).

Steps to Reproduce

  1. Open project folder in terminal
  2. Run ‘dotnet build -t:run -f:net6.0-ios -p:_DeviceName=insert_device_id_here /p:RuntimeIdentifier=ios-arm64 -c release’

Version with bug

Release Candidate 3 (current)

Last version that worked well

Unknown/Other

Affected platforms

iOS

Affected platform versions

iOS 15.4

Did you find any workaround?

no

Relevant log output

 System.ExecutionEngineException: Attempting to JIT compile method (wrapper delegate-invoke) int <Module>:invoke_callvirt_int_MyItem (reflecBug.MyItem) while running in aot-only mode. See https://docs.microsoft.com/xamarin/ios/internals/limitations for more information.
2022-05-16 15:16:40.965 reflecBug[93626:11651593]    at System.Linq.Expressions.Interpreter.FuncCallInstruction 2[[reflecBug.MyItem, reflecBug, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[System.Int32, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].Run(InterpretedFrame )
   at System.Linq.Expressions.Interpreter.Interpreter.Run(InterpretedFrame )
   at System.Linq.Expressions.Interpreter.LightLambda.Run(Object[] )
2022-05-16 15:16:40.965 reflecBug[93626:11651593]    at System.Dynamic.Utils.DelegateHelpers.FuncThunk1[Object,Object](Func`2 handler, Object t1)
   at reflecBug.MainPage.GetValue(Object component)
   at reflecBug.MainPage..ctor()

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 4
  • Comments: 33 (24 by maintainers)

Most upvoted comments

How did this even work in Xamarin.iOS Apps before and started breaking targeting net6.0-ios? This is a huge regression!

What happens is that linq creates a Func<MyItem,int> delegate in FuncCallInstruction<T0, TRet>:.ctor () without a target, then invokes it

As I wrote above: “The originally reported issue (“Attempting to JIT compile method”) might be related to what I called out in https://github.com/dotnet/runtime/pull/61952 in my comments around iDevices/iOS: there are more codepaths in S.L.Expressions that should be activated for a full AOT experience. Some of these codepaths require extra runtime support - it’s code around CanEmitObjectArrayDelegate and CanCreateArbitraryDelegates.”

Specifically to avoid landing in FuncCallInstruction..ctor, you either need to:

For NativeAOT, we set CanCreateArbitraryDelegates to false.

@ivanpovazan Still reproducing on my example from this issue (net8.0-ios | release | device) 😢

Thank you for checking it out, but unfortunately the fix is available only in preview 7.

Preview 7 is not available globally yet?

Correct. Preview 7 is not available officially yet. It will be released early to mid August.


I have verified that the sample works with the latest nightly build: 8.0.100-preview.7.23364.32, but will keep the issue open until it is not verified that the official preview 7 release includes the fix.

The ExecutionEngineException is supposed to be fixed in net8 by: https://github.com/dotnet/runtime/pull/85643

Unfortunately, that fix does not seem to resolve the issue reported here.

I have managed to reproduce the reported issue with https://github.com/dotnet/runtime/commit/fc75f7e15f6c99fe6805a96c45c93e4d7c460e68 on the main branch by adapting the HelloiOS accordingly and running it on a device.

Repro steps

  1. checkout current main branch
  2. apply this patch that sets up the HelloiOS sample app: https://gist.github.com/ivanpovazan/27cc90887e9709f0bd46579f9987e996
  3. build the repo with: ./build.sh mono+libs -c debug -os ios -arch arm64
  4. got to the sample dir: cd src/mono/sample/iOS
  5. run the sample: make run TARGET=ios MONO_ARCH=arm64
  6. inspect the console output with Console.app

The console log shows:

2023-06-21 16:22:27.691562+0200 HelloiOS[11803:4577363] System.ExecutionEngineException: Attempting to JIT compile method '(wrapper delegate-invoke) int System.Func`2<MyItem, int>:invoke_callvirt_TResult_T (MyItem)' while running in aot-only mode. See https://docs.microsoft.com/xamarin/ios/internals/limitations for more information.

Full log can be found here: https://gist.github.com/ivanpovazan/0f8bda708344858a6dd8c9efbddeea6c

What happens is that linq creates a Func<MyItem,int> delegate in FuncCallInstruction<T0, TRet>:.ctor () without a target, then invokes it

As I wrote above: “The originally reported issue (“Attempting to JIT compile method”) might be related to what I called out in #61952 in my comments around iDevices/iOS: there are more codepaths in S.L.Expressions that should be activated for a full AOT experience. Some of these codepaths require extra runtime support - it’s code around CanEmitObjectArrayDelegate and CanCreateArbitraryDelegates.”

Specifically to avoid landing in FuncCallInstruction..ctor, you either need to:

For NativeAOT, we set CanCreateArbitraryDelegates to false.

Couldn’t CanCreateArbitraryDelegates reflect RuntimeFeature.IsDynamicCodeSupported instead? That way it wouldn’t have to be special-cased everywhere.

private static bool CanCreateArbitraryDelegates => RuntimeFeature.IsDynamicCodeSupported;

Running with full-aot+interp fixes the ExecutionEngineException for me.

@rolfbjarne Is this mode supported in xam iOS?

Adding this to the csproj:

<PropertyGroup>
    <UseInterpreter>true</UseInterpreter>
</PropertyGroup>

will enable the interpreter, but still AOT every assembly (although I’m not sure if that’s equivalent to “full aot”).

Hello, we are developing DevExpress .NET MAUI controls and experienced the same issue a lot in our DevExpress.Data library that provides many helpful classes to our customers and for internal use. We use Expression.Compile() very widely in our codebase and we didn’t experience any issues with it in Xamarin.Forms, but experienced random crashes a lot in MAUI. There is another one same issue, that we’ve reported recently - dotnet/runtime#71323. That issues have a very high priority for us because we can’t release our components with random crashes. Could you provide any generic workaround for these issues? Thank you for your help.

@Eilon this should go to dotnet/runtime, it’s an issue with either the AOT compiler or the BCL.