Skip to content

Fix NativeAOT reverse delegate stub signature with runtime marshalling disabled#130239

Open
MichalStrehovsky wants to merge 3 commits into
dotnet:mainfrom
MichalStrehovsky:MichalStrehovsky/fix-84402-disabled-marshalling-delegate
Open

Fix NativeAOT reverse delegate stub signature with runtime marshalling disabled#130239
MichalStrehovsky wants to merge 3 commits into
dotnet:mainfrom
MichalStrehovsky:MichalStrehovsky/fix-84402-disabled-marshalling-delegate

Conversation

@MichalStrehovsky

Copy link
Copy Markdown
Member

The reverse delegate stub's native signature was computed via GetNativeMethodParameterType, which synthesizes a NativeType struct, without checking whether runtime marshalling is disabled for the delegate's module. The stub body, however, is emitted using CreateDisabledMarshaller (blittable pass-through), so the declared native signature disagreed with the emitted IL, tripping the 'ClassLayout::AreCompatible' assert during ILC importation.

Gate the native signature computation on IsRuntimeMarshallingEnabled(delegate module), matching PInvokeILEmitter.InitializeMarshallers and the CoreCLR VM (which uses the delegate Invoke method's module for m_pMetadataModule). When disabled, the native signature equals the managed signature.

Re-enables the previously disabled DisabledRuntimeMarshalling NativeAOT tests.

The test was also exercising some varargs scenarios and we were not throwing the right exception type for them. So fixing that too.

Fixes #84402

MichalStrehovsky and others added 3 commits July 6, 2026 15:58
…g disabled

The reverse delegate stub's native signature was computed via GetNativeMethodParameterType, which synthesizes a __NativeType__ struct, without checking whether runtime marshalling is disabled for the delegate's module. The stub body, however, is emitted using CreateDisabledMarshaller (blittable pass-through), so the declared native signature disagreed with the emitted IL, tripping the 'ClassLayout::AreCompatible' assert during ILC importation.

Gate the native signature computation on IsRuntimeMarshallingEnabled(delegate module), matching PInvokeILEmitter.InitializeMarshallers and the CoreCLR VM (which uses the delegate Invoke method's module for m_pMetadataModule). When disabled, the native signature equals the managed signature.

Re-enables the previously disabled DisabledRuntimeMarshalling NativeAOT tests.

Fixes dotnet#84402

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates NativeAOT’s interop/tooling pipeline so reverse delegate stubs compute a native signature consistent with disabled runtime marshalling behavior, and it aligns varargs handling with the expected exception type. It also re-enables previously excluded DisabledRuntimeMarshalling NativeAOT test projects.

Changes:

  • Update reverse delegate stub signature computation to use managed parameter/return types when runtime marshalling is disabled (matching the disabled marshaller’s blittable pass-through behavior).
  • Change several varargs-not-supported paths to throw InvalidProgramException instead of BadImageFormatException.
  • Remove NativeAotIncompatible from DisabledRuntimeMarshalling test csproj files to re-enable NativeAOT coverage.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/coreclr/tools/Common/TypeSystem/IL/Stubs/DelegateMarshallingMethodThunk.cs Gates native signature computation on runtime marshalling enablement to avoid __NativeType__ synthesis when disabled.
src/coreclr/tools/Common/TypeSystem/Ecma/EcmaSignatureParser.cs Treats SignatureTypeCode.Sentinel (varargs) as invalid program rather than bad image format.
src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs Updates varargs rejection to throw invalid program for unsupported varargs signatures.
src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs Updates varargs call import rejection to throw invalid program.
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/LibraryRootProvider.cs Updates varargs method rejection to throw invalid program.
src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_NativeAssemblyDisabled.csproj Re-enables NativeAOT by removing NativeAotIncompatible.
src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_Disabled_NativeTypeInAssembly.csproj Re-enables NativeAOT by removing NativeAotIncompatible.
src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_Disabled_NativeTypeInAssembly_ro.csproj Re-enables NativeAOT by removing NativeAotIncompatible.
src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_Disabled_NativeAssemblyDisabled.csproj Re-enables NativeAOT by removing NativeAotIncompatible.

Comment on lines +149 to +153
// When runtime marshalling is disabled, arguments and the return value are passed
// through blittably, so the native signature matches the managed signature.
var builder = new MethodSignatureBuilder(delegateSignature);
builder.Flags = MethodSignatureFlags.Static | unmanagedCallingConvention;
_signature = builder.ToSignature();
Comment on lines 461 to +463
_compilation.TypeSystemContext.EnsureLoadableMethod(method);
if ((method.Signature.Flags & MethodSignatureFlags.UnmanagedCallingConventionMask) == MethodSignatureFlags.CallingConventionVarargs)
ThrowHelper.ThrowBadImageFormatException();
ThrowHelper.ThrowInvalidProgramException();
Comment on lines 86 to 91
MethodSignature signature = method.Signature;

// Vararg methods are not supported in .NET Core
if ((signature.Flags & MethodSignatureFlags.UnmanagedCallingConventionMask) == MethodSignatureFlags.CallingConventionVarargs)
ThrowHelper.ThrowBadImageFormatException();
ThrowHelper.ThrowInvalidProgramException();

@MichalStrehovsky

Copy link
Copy Markdown
Member Author

/azp run runtime-nativeaot-outerloop

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DisabledRuntimeMarshalling_Disabled_NativeAssemblyDisabled failing with NativeAOT

2 participants