You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
NativeAOT: reflection on static abstract interface methods crashes in .NET 11 (10.0 throws NotSupportedException) #135565
On NativeAOT in .NET 11, reflection on a static abstract interface member calls through a null entry point. MethodInfo.Invoke, MethodInvoker.Invoke and PropertyInfo.GetValue crash the process with an access violation, a delegate from MethodInfo.CreateDelegate crashes when called, and RuntimeMethodHandle.GetFunctionPointer returns zero. On 10.0 all of these throw NotSupportedException. The change coincides with #125875, which made static virtual methods reflection-invokable on NativeAOT.
Reproduction Steps
usingSystem;usingSystem.Reflection;Run("MethodInfo.Invoke, ISortable.Sort",()=>typeof(ISortable).GetMethod("Sort")!.Invoke(null,null));Run("MethodInfo.Invoke, ISortable<int>.Sort(int)",()=>typeof(ISortable<int>).GetMethod("Sort")!.Invoke(null,newobject[]{1}));Run("MethodInvoker.Invoke, ISortable.Sort",()=>MethodInvoker.Create(typeof(ISortable).GetMethod("Sort")!).Invoke(null));Run("PropertyInfo.GetValue, ICounted.Count",()=>typeof(ICounted).GetProperty("Count")!.GetValue(null));Run("CreateDelegate, ISortable.Sort, then call",()=>typeof(ISortable).GetMethod("Sort")!.CreateDelegate<Action>()());Run("GetFunctionPointer, ISortable.Sort",()=>Console.WriteLine($"0x{typeof(ISortable).GetMethod("Sort")!.MethodHandle.GetFunctionPointer():X}"));Run("MethodInfo.Invoke, IDefault.Sort (static virtual with a body)",()=>typeof(IDefault).GetMethod("Sort")!.Invoke(null,null));staticvoidRun(stringlabel,Actionaction){try{action();Console.WriteLine($"{label}: no exception");}catch(Exceptione){Console.WriteLine($"{label}: {e.GetType()}: {e.Message}");}}publicinterfaceISortable{staticabstractvoidSort();}publicinterfaceISortable<T>{staticabstractvoidSort(Tvalue);}publicinterfaceICounted{staticabstractintCount{get;}}publicinterfaceIDefault{staticvirtualvoidSort(){}}
The six calls on static abstract members throw a managed exception; the last call prints no exception.
Actual behavior
The process prints nothing and exits with 0xC0000005 (access violation). Run one at a time, the four invoke calls and the delegate call each exit with 0xC0000005, GetFunctionPointer prints 0x0, and the static virtual call with a body prints no exception.
Regression?
Yes, from 10.0. The same program published with SDK 10.0.401 (net10.0, ILCompiler 10.0.12) prints System.NotSupportedException: This object cannot be invoked because no code was generated for it: 'ISortable.Sort()'. for the first call, the same exception for every other call, the static virtual one included, and exits 0.
PR #125875 (ac11e33, in release/11.0, not in release/10.0) removed this exclusion from MetadataManager.IsMethodSupportedInReflectionInvoke:
.NET SDK 11.0.100-rc.1.26420.103 with ILCompiler 11.0.0-rc.1.26420.103, Windows 11 x64, win-x64. For the 10.0 comparison, SDK 10.0.401 with ILCompiler 10.0.12.
Other information
Proposed fix: leave static abstract methods out of the reflection invoke map (MetadataManager.ShouldMethodBeInInvokeMap), keeping static virtual methods with a body invokable. That restores the 10.0 behaviour for all six calls, is a small compiler-only change, and suits a backport to release/11.0.
Options not taken:
Excluding static abstract methods in IsMethodSupportedInReflectionInvoke again. That method also drives dependency and dataflow analysis, so two ILCompiler.Trimming.Tests cases that Fix COMDelegate::BindToMethod with static virtuals #125875 updated fail: StaticInterfaceMethodDataflow (ImplIFoo.AbstractMethod() is no longer kept) and VirtualMethodHierarchyDataflowAnnotationValidation (IL2092, IL2093 and IL2095 warnings are missing).
I have a fix with a test ready and will open a PR for it shortly. Could this be assigned to me?
Note
AI-generated, written at my direction and reviewed by me before posting.
Verified on Windows 11 x64: the program above published with dotnet publish -c Release -r win-x64 -p:PublishAot=true using SDK 11.0.100-rc.1.26420.103 (exit 0xC0000005, no output) and, with net10.0, SDK 10.0.401 (the NotSupportedException output); the one-at-a-time results are from a copy of the program that runs only the call named on its command line. The commit's effect is from git show ac11e33bf5d and git merge-base --is-ancestor against origin/release/11.0 and origin/release/10.0; the code excerpts are from dotnet/runtime 2eb7113245f7c536ab876dca5e3533fb96c81bbf and from the parent of ac11e33. The proposed fix's result is the program above published with a compiler built locally from 2eb7113245f plus the fix; the trimming test failures are ILCompiler.Trimming.Tests run on the same commit with the first option not taken.
Description
On NativeAOT in .NET 11, reflection on a static abstract interface member calls through a null entry point.
MethodInfo.Invoke,MethodInvoker.InvokeandPropertyInfo.GetValuecrash the process with an access violation, a delegate fromMethodInfo.CreateDelegatecrashes when called, andRuntimeMethodHandle.GetFunctionPointerreturns zero. On 10.0 all of these throwNotSupportedException. The change coincides with #125875, which made static virtual methods reflection-invokable on NativeAOT.Reproduction Steps
Expected behavior
The six calls on static abstract members throw a managed exception; the last call prints
no exception.Actual behavior
The process prints nothing and exits with
0xC0000005(access violation). Run one at a time, the four invoke calls and the delegate call each exit with0xC0000005,GetFunctionPointerprints0x0, and the static virtual call with a body printsno exception.Regression?
Yes, from 10.0. The same program published with SDK 10.0.401 (
net10.0, ILCompiler 10.0.12) printsSystem.NotSupportedException: This object cannot be invoked because no code was generated for it: 'ISortable.Sort()'.for the first call, the same exception for every other call, the static virtual one included, and exits 0.PR #125875 (ac11e33, in
release/11.0, not inrelease/10.0) removed this exclusion fromMetadataManager.IsMethodSupportedInReflectionInvoke:MetadataManager.cs:427-429Static abstract methods now get invoke map entries, but the compiler only sets
HasEntrypointfor non-abstract methods:ReflectionInvokeMapNode.cs:164-165Known Workarounds
Not checked.
Configuration
.NET SDK 11.0.100-rc.1.26420.103 with ILCompiler 11.0.0-rc.1.26420.103, Windows 11 x64,
win-x64. For the 10.0 comparison, SDK 10.0.401 with ILCompiler 10.0.12.Other information
Proposed fix: leave static abstract methods out of the reflection invoke map (
MetadataManager.ShouldMethodBeInInvokeMap), keeping static virtual methods with a body invokable. That restores the 10.0 behaviour for all six calls, is a small compiler-only change, and suits a backport torelease/11.0.Options not taken:
IsMethodSupportedInReflectionInvokeagain. That method also drives dependency and dataflow analysis, so twoILCompiler.Trimming.Testscases that Fix COMDelegate::BindToMethod with static virtuals #125875 updated fail:StaticInterfaceMethodDataflow(ImplIFoo.AbstractMethod()is no longer kept) andVirtualMethodHierarchyDataflowAnnotationValidation(IL2092, IL2093 and IL2095 warnings are missing).MemberAccessException, the exception I'll propose for Incorrect error message when trying to dynamically invoke a static abstract interface method #101320 (PR to follow). It depends on that change, so it belongs with it rather than in a backportable regression fix.I have a fix with a test ready and will open a PR for it shortly. Could this be assigned to me?
Note
AI-generated, written at my direction and reviewed by me before posting.
Verified on Windows 11 x64: the program above published with
dotnet publish -c Release -r win-x64 -p:PublishAot=trueusing SDK 11.0.100-rc.1.26420.103 (exit0xC0000005, no output) and, withnet10.0, SDK 10.0.401 (theNotSupportedExceptionoutput); the one-at-a-time results are from a copy of the program that runs only the call named on its command line. The commit's effect is fromgit show ac11e33bf5dandgit merge-base --is-ancestoragainstorigin/release/11.0andorigin/release/10.0; the code excerpts are from dotnet/runtime2eb7113245f7c536ab876dca5e3533fb96c81bbfand from the parent of ac11e33. The proposed fix's result is the program above published with a compiler built locally from2eb7113245fplus the fix; the trimming test failures areILCompiler.Trimming.Testsrun on the same commit with the first option not taken.