Skip to content

Comments

[release/10.0] PersistedAssemblyBuilder: Fix encoding of custom modifiers. (#123925)#124537

Open
jkotas wants to merge 3 commits intodotnet:release/10.0from
jkotas:backport-123857
Open

[release/10.0] PersistedAssemblyBuilder: Fix encoding of custom modifiers. (#123925)#124537
jkotas wants to merge 3 commits intodotnet:release/10.0from
jkotas:backport-123857

Conversation

@jkotas
Copy link
Member

@jkotas jkotas commented Feb 18, 2026

Backport of #119935, #121128, #123925 to release/10.0

Customer Impact

  • Customer reported
  • Found internally

Unable to emit references to methods and fields with signatures that include modopts and modreqs using PersistedAssemblyBuilder (e.g. method signatures that use C# readonly ref or in).

Regression

  • Yes
  • No

This is a bug in PersistedAssemblyBuilder that shipped in .NET 9. Adoption blocker with no workaround.

Testing

Dedicated tests.

Risk

Medium. The change is a combination of 3 different PRs that fixed different aspects of the bug. The size of the delta makes is a medium risk.

@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-system-reflection-emit
See info in area-owners.md if you want to be subscribed.

Copy link
Contributor

Copilot AI left a comment

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 fixes a critical bug in PersistedAssemblyBuilder where custom modifiers (like InAttribute on in parameters) were not being correctly encoded in method signatures when using types obtained via GetModifiedParameterType(). The issue manifested as a TypeLoadException when loading assemblies with interface implementations that have custom modifiers on parameters.

Changes:

  • Refactored signature encoding to always extract custom modifiers from types when modifier arrays are null
  • Added a test to verify interface overrides with custom modifiers work correctly
  • Improved code clarity with better variable naming and simplified array encoding

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/SignatureHelper.cs Core fix: Modified WriteSignatureForType to extract custom modifiers from types when modifier arrays are null; unified signature encoding logic across fields, methods, properties, and parameters; simplified array encoding
src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveTypeBuilderTests.cs Added regression test SaveInterfaceOverrideWithCustomModifier that validates the fix by creating an interface override with in parameter modifiers and verifying the assembly loads without errors
src/libraries/System.Reflection.Emit/tests/PersistedAssemblyBuilder/AssemblySaveILGeneratorTests.cs Renamed variable nestedParam to sectorParam for better code clarity
src/libraries/System.Reflection.Emit/tests/System.Reflection.Emit.Tests.csproj Ensured project reference to System.Reflection.Emit source project

Copilot AI review requested due to automatic review settings February 18, 2026 07:58
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

jgh07 and others added 3 commits February 19, 2026 14:49
…119935)

This fixes dotnet#111003. The current implementation is a **work in progress**, only **managed** function pointers with no modopts are supported.

---------

Co-authored-by: Jan Kotas <jkotas@microsoft.com>
…#123925)

Fixes dotnet#123857.

---------

Co-authored-by: Jan Kotas <jkotas@microsoft.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 5 comments.

Comment on lines +178 to +184
public FunctionPointer(
Type baseFunctionPointerType,
Type[] conventions = null,
Type customReturnType = null,
Type[] customParameterTypes = null,
Type[] fnPtrRequiredMods = null,
Type[] fnPtrOptionalMods = null)
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

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

FunctionPointer ctor uses non-nullable parameters with null defaults (e.g., Type[] conventions = null, Type customReturnType = null). With repo-wide TreatWarningsAsErrors=true, this will fail compilation (CS8625). Make these parameters nullable (Type[]?, Type?, etc.) or remove the null defaults.

Copilot uses AI. Check for mistakes.
private readonly Type[] requiredModifiers;
private readonly Type[] optionalModifiers;

public ModifiedType(Type delegatingType, Type[] requiredMods = null, Type[] optionalMods = null)
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

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

ModifiedType ctor also uses non-nullable array parameters with null defaults (Type[] requiredMods = null, Type[] optionalMods = null), which will produce nullable warnings treated as errors. Update the parameter types to nullable (Type[]?) or avoid null defaults.

Suggested change
public ModifiedType(Type delegatingType, Type[] requiredMods = null, Type[] optionalMods = null)
public ModifiedType(Type delegatingType, Type[]? requiredMods = null, Type[]? optionalMods = null)

Copilot uses AI. Check for mistakes.
Comment on lines +891 to +893
FieldInfo field2 = testType.GetField("FuncPtr2");
Type field2Type = field2.GetModifiedFieldType();
Assert.NotNull(field2);
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

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

field2 is dereferenced before the null-check: field2Type = field2.GetModifiedFieldType(); runs before Assert.NotNull(field2). If the field lookup fails, this will throw NullReferenceException instead of a test assertion. Move the Assert.NotNull(field2) before calling GetModifiedFieldType().

Copilot uses AI. Check for mistakes.
@teo-tsirpanis teo-tsirpanis added this to the 10.0.x milestone Feb 20, 2026
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.

4 participants