Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Sep 3, 2025

This PR fixes a bug in Mono's implementation where CustomAttributeTypedArgument.Value was not returning the documented ReadOnlyCollection<CustomAttributeTypedArgument> for array arguments, causing an InvalidCastException in the ToString() method.

Problem

The issue occurred when accessing custom attributes with array parameters on Mono. For example:

using System;
using System.Linq;
using System.Reflection;

var attr = typeof(C).CustomAttributes.Single(d => d.AttributeType == typeof(A));
var arg = attr.ConstructorArguments.Single();
Console.WriteLine(arg.ToString()); // Throws InvalidCastException on Mono

class A : Attribute
{
    public unsafe A(params B<delegate*<void>[]>.E[] a) { }
} 

class B<T>
{
    public enum E { }
}

[A(new B<delegate*<void>[]>.E())]
unsafe class C { }

On Mono, this would throw:

System.InvalidCastException: Specified cast is not valid.
   at System.Reflection.CustomAttributeTypedArgument.ToString(Boolean typed)

Root Cause

The ToString() method in CustomAttributeTypedArgument expects array values to be IList<CustomAttributeTypedArgument>, but Mono was returning the raw array type instead of wrapping it in a ReadOnlyCollection<CustomAttributeTypedArgument> as documented and as implemented in CoreCLR.

Solution

Following feedback from @jkotas, the fix was implemented in Mono's native code rather than the shared managed code:

  1. Modified create_cattr_typed_arg: Updated this function in Mono's custom-attrs.c to detect array arguments and convert each array element to a CustomAttributeTypedArgument
  2. Array Element Transformation: When the argument type is an array, each element is recursively wrapped in a CustomAttributeTypedArgument
  3. Shared Code Support: Added minimal support in the shared CanonicalizeValue method to convert CustomAttributeTypedArgument[] to ReadOnlyCollection<CustomAttributeTypedArgument> using Array.AsReadOnly()

This approach ensures the fix is specific to Mono's implementation while maintaining compatibility with CoreCLR's existing behavior.

Testing

  • Verified the comprehensive test case Test_CustomAttributeTypedArgument_ArrayValue_ShouldBeReadOnlyCollection passes
  • Confirmed existing Test_CustomAttributeTypedArgument_ToString test continues to pass
  • Tested the original issue scenario successfully - no more InvalidCastException
  • Output now matches CoreCLR behavior correctly

Fixes #119292.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

@jkotas
Copy link
Member

jkotas commented Sep 3, 2025

@copilot The fix is likely needed in ves_icall_System_Reflection_RuntimeCustomAttributeData_ResolveArgumentsInternal or one of the methods that it calls.

@github-actions github-actions bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Sep 3, 2025
Copilot AI changed the title [WIP] [Mono] CustomAttributeTypedArgument.Value should return ReadOnlyCollection<CustomAttributeTypedArgument> for arrays [Mono] Fix CustomAttributeTypedArgument.Value to return ReadOnlyCollection for arrays Sep 3, 2025
Copilot finished work on behalf of jkotas September 3, 2025 01:53
Copilot AI requested a review from jkotas September 3, 2025 01:53
Copy link
Contributor Author

Copilot AI commented Sep 3, 2025

@copilot The fix is likely needed in ves_icall_System_Reflection_RuntimeCustomAttributeData_ResolveArgumentsInternal or one of the methods that it calls.

Thanks for the guidance! I've implemented the fix in the create_cattr_typed_arg function in Mono's custom-attrs.c as suggested. The fix detects when the argument type is an array and converts each array element to a CustomAttributeTypedArgument, creating an array that gets properly converted to ReadOnlyCollection by the shared CanonicalizeValue method. The original issue is now resolved and tests pass. Commit: 586b1e9

Copilot AI changed the title [Mono] Fix CustomAttributeTypedArgument.Value to return ReadOnlyCollection for arrays [Mono] Fix CustomAttributeTypedArgument.Value to return ReadOnlyCollection for arrays in native code Sep 3, 2025
Copilot finished work on behalf of jkotas September 3, 2025 02:30
@jkotas jkotas closed this Sep 3, 2025
@jkotas jkotas deleted the copilot/fix-119292 branch September 8, 2025 17:33
@github-actions github-actions bot locked and limited conversation to collaborators Oct 9, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Mono] CustomAttributeTypedArgument.Value should return ReadOnlyCollection<CustomAttributeTypedArgument> for arrays

2 participants