Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AOT enums with generic attributes don't support any reflection at all; System.Enum Get...() methods all throw exceptions. #111578

Closed
crankywilson opened this issue Jan 18, 2025 · 5 comments · Fixed by #111585
Labels
area-NativeAOT-coreclr in-pr There is an active PR which will close this issue when it is merged

Comments

@crankywilson
Copy link

crankywilson commented Jan 18, 2025

Description

Eric Erhardt makes the claim in https://devblogs.microsoft.com/dotnet/creating-aot-compatible-libraries/ that if you don't get warnings, there shouldn't be different behavior in AOT... However, I have found that there is no support for doing anything with enums on linux except assigning and comparing. For example, I get a warning that "Using member 'System.Enum.GetValues(Type)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. It might not be possible to create an array of the enum type at runtime. Use the GetValues overload or the GetValuesAsUnderlyingType method instead." But using either of the suggestions (which gets rid of the warnings) still results in an UnsupportedException at runtime. In fact, everything I tried with enums results in an unsupported exception.

I found that for non-enum objects, I can slap a [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] attribute which allows reflection to work great. But enums do not support this attribute, I couldn't find any other kind of attribute to give a hint that I want to keep the values in the assembly.

This seems like such a basic/core piece of functionality... It would be nice if a solution could be found for this.

Reproduction Steps

Create a console dotnet application.

csproj needs these added:

    <PublishAot>true</PublishAot>
    <InvariantGlobalization>true</InvariantGlobalization>
    <PublishTrimmed>true</PublishTrimmed>

to PropertyGroup

In the .cs file, simply

Define
enum Color { R, Y, G, B, C, N }
and have a statement that does
Enum.GetValues<Color>();

Expected behavior

no crashes

Actual behavior

Unhandled exception. System.NotSupportedException: Specified method is not supported.
at System.Reflection.Runtime.General.NativeFormatMetadataReaderExtensions.IsCustomAttributeOfType(CustomAttributeHandle, MetadataReader, ReadOnlySpan`1, String) + 0x466

Regression?

No response

Known Workarounds

No response

Configuration

(linux dotnet 8/9)

Other information

No response

@dotnet-issue-labeler dotnet-issue-labeler bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Jan 18, 2025
@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label Jan 18, 2025
@jkotas jkotas removed the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Jan 18, 2025
@jkotas
Copy link
Member

jkotas commented Jan 18, 2025

I am not able to reproduce the issue on .NET 9.

Do you have <IlcDisableReflection>true</IlcDisableReflection> property set in your project by a chance? Setting this experimental property would result into behavior that you are seeing. This experimental property does not exist anymore.

@jkotas jkotas added the needs-author-action An issue or pull request that requires more info or actions from the author. label Jan 18, 2025
@crankywilson
Copy link
Author

crankywilson commented Jan 19, 2025

Nope, my full csproj looks like this:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <PublishAot>true</PublishAot>
    <InvariantGlobalization>true</InvariantGlobalization>
    <PublishTrimmed>true</PublishTrimmed>
    <JsonSerializerIsReflectionEnabledByDefault>true</JsonSerializerIsReflectionEnabledByDefault>
  </PropertyGroup>

</Project>

So it is possible to get enum value/names in AOT in at least some configuration?

It's possible my linux setup is bit Frankenstein-ish... I had some difficulty getting dotnet 9 on my Linux Mint since it wasn't offered by the standard software repos yet...

Are you (joktas) actually running on Linux?

Maybe I'll try following my own steps from scratch to see if I have any better luck. I am using a much bigger project than what I posted.

@dotnet-policy-service dotnet-policy-service bot removed the needs-author-action An issue or pull request that requires more info or actions from the author. label Jan 19, 2025
@crankywilson
Copy link
Author

test62.tar.gz

Well, when I start from nothing and just do the simple test, it in fact works for me too!
I'm attaching my 'bad' project to this -- I will see if I can pinpoint what about it causes the enum parsing to not work. My enums have custom attributes on them, not sure if that's the problem yet or not.

In this, my program.cs has var a =Enum.GetValues<Color>(); on line 16 that is crashing. (But only in Release AOT) The exception stack trace doesn't offer line #s but I've done enough adjusting that I'm very sure that is the offending line.

@crankywilson
Copy link
Author

Ok, I think I figured it out. So if my enum has a generic attribute on it, that's when it doesn't work. "Normal" attributes are fine... I'm not sure what about generic attributes causes the problem, but here is a simple example that fails:

foreach (var e in Enum.GetValues<Color>())
  Console.WriteLine(e);

[CustomAttribute<int>]
enum Color { R, Y, G, B }

internal class CustomAttribute<T> : Attribute
{
}

(At first I thought maybe it was the self-referential types in my attachment above, but it doesn't seem to matter what the argument type is)

I was looking for an easy-ish way to mark my enums in a way that I could automatically-ish get the names and values to make sure they will match up with with remote instances of other programs running. I'll see if I can find one that doesn't involve generic attributes.

@crankywilson crankywilson changed the title AOT enums don't support any reflection at all on linux; System.Enum Get...() methods all throw exceptions. AOT enums with generic attributes don't support any reflection at all on linux; System.Enum Get...() methods all throw exceptions. Jan 19, 2025
@hez2010
Copy link
Contributor

hez2010 commented Jan 19, 2025

It seems that we didn't handle TypeSpecification here:

public static bool IsCustomAttributeOfType(this CustomAttributeHandle customAttributeHandle,

/cc: @MichalStrehovsky

@dotnet-policy-service dotnet-policy-service bot added the in-pr There is an active PR which will close this issue when it is merged label Jan 19, 2025
@jkotas jkotas changed the title AOT enums with generic attributes don't support any reflection at all on linux; System.Enum Get...() methods all throw exceptions. AOT enums with generic attributes don't support any reflection at all; System.Enum Get...() methods all throw exceptions. Jan 19, 2025
@dotnet-policy-service dotnet-policy-service bot removed the untriaged New issue has not been triaged by the area owner label Jan 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-NativeAOT-coreclr in-pr There is an active PR which will close this issue when it is merged
Projects
Status: No status
Development

Successfully merging a pull request may close this issue.

3 participants