[release/10.0] PersistedAssemblyBuilder: Fix encoding of custom modifiers. (#123925)#124537
[release/10.0] PersistedAssemblyBuilder: Fix encoding of custom modifiers. (#123925)#124537jkotas wants to merge 3 commits intodotnet:release/10.0from
PersistedAssemblyBuilder: Fix encoding of custom modifiers. (#123925)#124537Conversation
|
Tagging subscribers to this area: @dotnet/area-system-reflection-emit |
61f807d to
1176aa9
Compare
There was a problem hiding this comment.
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 |
1176aa9 to
4c94d43
Compare
4c94d43 to
349b9f7
Compare
…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>
349b9f7 to
eefcb22
Compare
| public FunctionPointer( | ||
| Type baseFunctionPointerType, | ||
| Type[] conventions = null, | ||
| Type customReturnType = null, | ||
| Type[] customParameterTypes = null, | ||
| Type[] fnPtrRequiredMods = null, | ||
| Type[] fnPtrOptionalMods = null) |
There was a problem hiding this comment.
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.
| private readonly Type[] requiredModifiers; | ||
| private readonly Type[] optionalModifiers; | ||
|
|
||
| public ModifiedType(Type delegatingType, Type[] requiredMods = null, Type[] optionalMods = null) |
There was a problem hiding this comment.
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.
| public ModifiedType(Type delegatingType, Type[] requiredMods = null, Type[] optionalMods = null) | |
| public ModifiedType(Type delegatingType, Type[]? requiredMods = null, Type[]? optionalMods = null) |
| FieldInfo field2 = testType.GetField("FuncPtr2"); | ||
| Type field2Type = field2.GetModifiedFieldType(); | ||
| Assert.NotNull(field2); |
There was a problem hiding this comment.
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().
Backport of #119935, #121128, #123925 to release/10.0
Customer Impact
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 reforin).Regression
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.