Do not allow generic inlining of ldftn requiring a fat function pointer - #131439
Conversation
When `ldftn` targets a method that needs a hidden generic context argument, ILC asks the JIT to build a fat function pointer and creates a `MethodEntry` generic lookup helper for it. Unlike every other lookup path, this one did not check whether the token came from an inlinee's generic context, so the runtime determined method (expressed in the inlinee's generic parameters) ended up recorded in the inliner's dictionary. Instantiating those dependencies then threw `IndexOutOfRangeException` in `GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution`, or silently produced a lookup against the wrong dictionary. Abort the inline in that case, the same way we do for delegate creation (dotnet#102299) and for `ComputeLookup`. Fixes dotnet#129093. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4a16e444-be00-4ff2-a37a-f3c3ea4eef4e
|
Azure Pipelines: Successfully started running 3 pipeline(s). 13 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
|
Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib |
There was a problem hiding this comment.
Pull request overview
Prevents NativeAOT/ILC from allowing inlining when importing an ldftn that would require a fat function pointer lookup expressed in the inlinee’s generic context, by reporting the lookup as unsupported in that situation. Adds a NativeAOT smoke-test regression to cover the crash scenario.
Changes:
- In
CorInfoImpl.getCallInfo, detectldftnfat-function-pointer runtime lookups coming from an inlinee token context and returnCORINFO_LOOKUP_NOT_SUPPORTEDto force the JIT to abort the inline. - Add a NativeAOT smoke-test regression (
Test129093Regression) that takes a function pointer to a generic method requiring a generic context and validates correctness for multiple instantiations.
Show a summary per file
| File | Description |
|---|---|
| src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs | Returns CORINFO_LOOKUP_NOT_SUPPORTED for fat-function-pointer ldftn lookups when the token context doesn’t match the method being compiled (inlining case). |
| src/tests/nativeaot/SmokeTests/UnitTests/Generics.cs | Adds Test129093Regression and wires it into the NativeAOT Generics smoke test run list. |
Copilot's findings
- Files reviewed: 2/2 changed files
- Comments generated: 1
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
MichalStrehovsky
left a comment
There was a problem hiding this comment.
Good catch! Seems like not async specific and not a .NET 11 regression. Looks like I almost fixed this in #129560 when someone on Discord was asking why we're even doing a R2R helper here (we shouldn't be doing a R2R helper in the first place, but the R2R helper is an easier way out considering everything else).
|
Bravo! |
Fixes #129093.
When
ldftntargets a method that needs a hidden generic context argument, ILC asks the JIT to build a fat function pointer and creates aReadyToRunHelperId.MethodEntrygeneric lookup helper for it. Unlike every other lookup path inCorInfoImpl(ComputeLookup, and the delegate ctor path fixed in #102299), this one did not check whether the token came from an inlinee's generic context.The result is that the runtime determined method - expressed in terms of the inlinee's generic parameters - ends up recorded in the inliner's dictionary.
ShadowMethodNode.GetStaticDependenciesthen substitutes it with the inliner's instantiations, which throwsIndexOutOfRangeExceptioninGetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitutionwhen the arities don't line up (and would silently look up the wrong dictionary slot when they do).Repro (crashes
ilcwith the stack reported in #129093):The fix aborts the inline in that case, which the JIT already knows how to handle (
impLookupToTreenotesCALLSITE_GENERIC_DICTIONARY_LOOKUPforCORINFO_LOOKUP_NOT_SUPPORTED, and bothimpMethodPointercallers checkcompDonotInline).Validation:
Index was outside the bounds of the arrayerror without the compiler change, and passes with it.src/tests/nativeaottree builds and the produced binaries run clean on linux-x64.Cc @dotnet/ilc-contrib
Note
This change was authored with GitHub Copilot.