[ILLink] Fix crash when array types are used as TypeMap trim targets with PublishTrimmed#126380
[ILLink] Fix crash when array types are used as TypeMap trim targets with PublishTrimmed#126380
Conversation
Strip parameterized types (array, pointer, etc.) from TypeMap trim targets and source types, using the element type instead. This fixes the crash when typeof(SomeType[]) is used as a trim target in TypeMap attributes during PublishTrimmed. Add test cases for array type trim targets (used and unused) to TypeMap.cs. Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/82e75422-6094-47d8-be6f-7a4527457908 Co-authored-by: jkoritzinsky <1571408+jkoritzinsky@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Fixes an ILLink crash in PublishTrimmed when TypeMap attributes specify non-resolvable TypeSpecification types (notably arrays) as trim targets by stripping wrappers down to a resolvable element type before calling LinkContext.Resolve.
Changes:
- Normalize
TypeMaptrim targets and association source types by unwrappingTypeSpecification(array/pointer/byref/…) to an element type until reaching aTypeDefinitionorGenericInstanceType. - Add new linker test coverage for an array-type trim target scenario (kept case), and introduce a second unused-case scenario that should assert removal.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/tools/illink/src/linker/Linker/TypeMapHandler.cs |
Unwraps TypeSpecification wrappers before resolving trim targets / proxy source types to avoid NotSupportedException crashes. |
src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeMap.cs |
Adds test inputs for array-type trim targets and ensures at least the reachable-element case is preserved. |
- Add RemovedTypeInAssembly("test", ...) for unused array trim target types
to make the expected removal behavior explicit
- Fix misleading comment in AddProxyTypeMapEntry: TypeMapAssociationAttribute
has two constructor type arguments (source and proxy), not one
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/8d0dbb63-91fb-4d87-8ccd-60e91da2e1e9
Co-authored-by: jkoritzinsky <1571408+jkoritzinsky@users.noreply.github.com>
Done in af0ac93:
Both |
|
Note This review was generated by Copilot. TypeMapHandler PR Review✅ Core fix is correct and well-targetedThe
The loop terminates safely because each iteration removes one wrapper layer from a finite chain. Excluding
|
|
@copilot please apply the same fix in MarkTypeMapAttribute as the review identified and use the pattern matching style it recommends throughout your changes. |
…se property pattern matching style
- Strip TypeSpecification wrappers in MarkTypeMapAttribute before calling
_context.Resolve(targetType), same as AddExternalTypeMapEntry/AddProxyTypeMapEntry
- Use property pattern matching style (TypeSpecification { ElementType: var elementType })
in all three stripping loops to avoid explicit casts
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/83c6e763-b98c-4183-b1b6-03ae760139de
Co-authored-by: jkoritzinsky <1571408+jkoritzinsky@users.noreply.github.com>
Done in 7ecb95a:
|
|
/azp run runtime,runtime-dev-innerloop,dotnet-linker-tests |
|
Azure Pipelines successfully started running 3 pipeline(s). |
PublishTrimmedcrashes withNotSupportedException: TypeDefinition cannot be resolved from 'Mono.Cecil.ArrayType'when aTypeMapattribute specifies an array type as its trim target (e.g.,typeof(Foo[])).PublishAotis unaffected (handled in #123031).Root cause:
LinkContext.Resolvethrows for anyTypeSpecificationthat isn't aGenericInstanceType. Array types, pointer types, and byref types all fall into this category.Description
TypeMapHandler.AddExternalTypeMapEntry: Strip non-resolvableTypeSpecificationwrappers (array, pointer, byref, etc.) from the trim target before passing toRecordTypeMapEntry, using the element type instead. Loop terminates at the firstTypeDefinitionorGenericInstanceType(both resolvable).TypeMapHandler.AddProxyTypeMapEntry: Same fix applied symmetrically to the source type parameter. Corrected the comment to accurately state thatTypeMapAssociationAttributehas two constructor type arguments (source and proxy).TypeMapHandler.MarkTypeMapAttribute: SameTypeSpecification-stripping fix applied before calling_context.Resolve(targetType), preventing the crash when a reachable entry's target type is an array or other parameterized type.TypeSpecification { ElementType: var elementType }) to avoid explicit casts.The loop handles nested arrays (
Foo[][]→Foo), pointer types, and mixed cases likeList<Foo>[](strips toList<Foo>, which is aGenericInstanceTypeand resolvable).Customer Impact
PublishTrimmedbuilds fail with an unhandledNotSupportedException/ fatal ILLink error when any assembly attribute uses an array type as aTypeMaptrim target. No workaround short of removing the array type.Regression
No — this is a new feature (
TypeMap) that never handled array trim targets correctly in ILLink.Testing
Added test cases to
TypeMap.cs:TrimTargetIsUsedArrayType: array trim target whose element type is reachable — attribute must be preserved; verified withKeptAttributeAttribute.TrimTargetIsUnusedArrayType: array trim target whose element type is unreachable — attribute and target types are removed; verified with explicitRemovedTypeInAssembly("test", ...)assertions on bothArrayTypeTrimTargetUnusedClassandArrayTypeTrimTargetUnusedTarget.Both existing
Reflection.TypeMapandReflection.TypeMapEntryAssemblytests pass.Risk
Low. The change is localized to three private methods in
TypeMapHandler. The stripping logic mirrors the existingTypeSpecification/GenericInstanceTypeguard already present inLinkContext.Resolve. No behavior change for existing valid (non-array) trim targets.Package authoring no longer needed in .NET 9
IMPORTANT: Starting with .NET 9, you no longer need to edit a NuGet package's csproj to enable building and bump the version.
Keep in mind that we still need package authoring in .NET 8 and older versions.