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

NativeAOT: Type.BaseType throws exeption when there is no basetype in reflection-free-mode #66810

Closed
josephmoresena opened this issue Mar 18, 2022 · 1 comment · Fixed by #66955
Labels
area-NativeAOT-coreclr help wanted [up-for-grabs] Good issue for external contributors
Milestone

Comments

@josephmoresena
Copy link
Contributor

josephmoresena commented Mar 18, 2022

Description

I am trying to check if a type is or inherits from another. Type.IsAssignableTo(Type) and Type.IsSubclassOf(Type) are not on the list of working APIs, but Type.BaseType is.
The problem occurs when I try to get the base type of a type that doesn't have one.

Reproduction Steps

Classes.cs

public abstract class A { }
public class B : A { }
public class C : A { }
public abstract class Z : B { }
public class Y : Z { }
public class X : C { }

public static class Extensions
{
    public static Boolean IsOrInheritsFrom(this Type type, Type expectedType)
    {
        Type? baseType = type;
        while (baseType is not null)
        {
            if (baseType.Equals(expectedType))
                return true;
            baseType = baseType?.BaseType;
        }
        return false;
    }
}

Program.cs

Dictionary<Type, String> types = new()
{
    { typeof(A), nameof(A) },
    { typeof(B), nameof(B) },
    { typeof(C), nameof(C) },
    { typeof(Z), nameof(Z) },
    { typeof(Y), nameof(Y) },
    { typeof(X), nameof(X) },
};

foreach (Type type in types.Keys)
    foreach (Type type2 in types.Keys)
        Console.WriteLine($"{types[type]} -> {type.IsOrInheritsFrom(type2)} <- {types[type2]}");

NativeAOTIssue.csproj

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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.DotNet.ILCompiler" Version="7.0.0-*" />
  </ItemGroup>
	
</Project>

Compile the project using NativeAOT dotnet publish -r win-x64 /p:IlcDisableReflection=true
Execute native binary .\bin\Debug\net6.0\win-x64\publish\NativeAOTIssue.exe

Expected behavior

A -> True <- A
A -> False <- B
A -> False <- C
A -> False <- Z
A -> False <- Y
A -> False <- X
B -> True <- A
B -> True <- B
B -> False <- C
B -> False <- Z
B -> False <- Y
B -> False <- X
C -> True <- A
C -> False <- B
C -> True <- C
C -> False <- Z
C -> False <- Y
C -> False <- X
Z -> True <- A
Z -> True <- B
Z -> False <- C
Z -> True <- Z
Z -> False <- Y
Z -> False <- X
Y -> True <- A
Y -> True <- B
Y -> False <- C
Y -> True <- Z
Y -> True <- Y
Y -> False <- X
X -> True <- A
X -> False <- B
X -> True <- C
X -> False <- Z
X -> False <- Y
X -> True <- X

Actual behavior

A -> True <- A
Unhandled Exception: EETypeRva:0x0021E3B8: Arg_NullReferenceException
   at Internal.Runtime.MethodTable.get_Kind() + 0xf
   at Internal.Runtime.MethodTable.get_IsGenericTypeDefinition() + 0x18
   at System.EETypePtr.get_IsGenericTypeDefinition() + 0x1b
   at Internal.Runtime.Augments.RuntimeAugments.TryGetBaseType(RuntimeTypeHandle, RuntimeTypeHandle&) + 0x45
   at Internal.Reflection.RuntimeTypeInfo.get_BaseType() + 0x29
   at Extensions.IsOrInheritsFrom(Type, Type) + 0x91
   at Program.<Main>$(String[]) + 0x3bc
   at NativeAOTIssue!<BaseAddress>+0x1c6907
   at NativeAOTIssue!<BaseAddress>+0x1c6995

Regression?

No response

Known Workarounds

No response

Configuration

.NET: 6.0
OS: Windows 10 21H2
Arch: x64

Other information

No response

@MichalStrehovsky
Copy link
Member

The problem is in the implementation of BaseType. Apparently, RuntimeAugments.TryGetBaseType will succeed, but return a default RuntimeTypeHandle for System.Object. We should instead take the same path as if TryGetBaseType failed.

public override Type BaseType
{
get
{
if (RuntimeAugments.TryGetBaseType(_typeHandle, out RuntimeTypeHandle baseTypeHandle))
{
return GetRuntimeTypeInfo(baseTypeHandle);
}
return null;
}
}

@MichalStrehovsky MichalStrehovsky added this to the Future milestone Mar 18, 2022
@MichalStrehovsky MichalStrehovsky added the help wanted [up-for-grabs] Good issue for external contributors label Mar 18, 2022
@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Mar 21, 2022
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Mar 22, 2022
@ghost ghost locked as resolved and limited conversation to collaborators Apr 21, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-NativeAOT-coreclr help wanted [up-for-grabs] Good issue for external contributors
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants