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

[Mono] System.Runtime.Tests fail with TypeLoadException #94086

Closed
adamsitnik opened this issue Oct 27, 2023 · 3 comments · Fixed by #94835
Closed

[Mono] System.Runtime.Tests fail with TypeLoadException #94086

adamsitnik opened this issue Oct 27, 2023 · 3 comments · Fixed by #94835
Labels
area-System.Runtime runtime-mono specific to the Mono runtime
Milestone

Comments

@adamsitnik
Copy link
Member

In #88620 I've added a very simple code that performs following checks:

private static void ValidateArrayType(Type arrayType)
{
    if (!arrayType.IsArray)
        ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_HasToBeArrayClass, ExceptionArgument.arrayType);

    ValidateElementType(arrayType.GetElementType()!);
}

private static void ValidateElementType(Type elementType)
{
    while (elementType.IsArray)
    {
        elementType = elementType.GetElementType()!;
    }

    if (elementType.IsByRef || elementType.IsByRefLike)
        ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ByRefLikeArray);
    if (elementType == typeof(void))
        ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_VoidArray);
    if (elementType.ContainsGenericParameters)
        ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_OpenType);
}

The tests pass on CLR and NativeAOT, but fail on Mono:

    System.Tests.ArrayTests.CreateInstanceFromArrayType_NotSupportedArrayType_ThrowsNotSupportedException(elementType: typeof(System.Void)) [FAIL]
      Assert.Throws() Failure: Exception type was not an exact match
      Expected: typeof(System.NotSupportedException)
      Actual:   typeof(System.TypeLoadException)
      ---- System.TypeLoadException : Could not load array element class, due to: Error getting the interfaces of System.Void[] due to Error Loading class assembly:/root/helix/work/correlation/shared/Microsoft.NETCore.App/9.0.0/System.Private.CoreLib.dll type:IList`1 member:(null) assembly:/root/helix/work/correlation/shared/Microsoft.NETCore.App/9.0.0/System.Private.CoreLib.dll type:Void[] member:(null)
      Stack Trace:
        /_/src/libraries/System.Runtime/tests/System/ArrayTests.cs(1957,0): at System.Tests.ArrayTests.CreateInstanceFromArrayType_NotSupportedArrayType_ThrowsNotSupportedException(Type elementType)
        /_/src/mono/System.Private.CoreLib/src/System/Reflection/MethodBaseInvoker.Mono.cs(22,0): at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
        /_/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodBaseInvoker.cs(178,0): at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr)
        ----- Inner Stack Trace -----
        /_/src/mono/System.Private.CoreLib/src/System/RuntimeTypeHandle.cs(287,0): at System.RuntimeTypeHandle.GetElementType(RuntimeType type)
        /_/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs(96,0): at System.RuntimeType.GetElementType()
        /_/src/libraries/System.Private.CoreLib/src/System/Array.cs(338,0): at System.Array.ValidateArrayType(Type arrayType)
        /_/src/libraries/System.Private.CoreLib/src/System/Array.cs(261,0): at System.Array.CreateInstanceFromArrayType(Type arrayType, Int32[] lengths)
        /_/src/libraries/System.Runtime/tests/System/ArrayTests.cs(1957,0): at System.Tests.ArrayTests.<>c__DisplayClass90_0.<CreateInstanceFromArrayType_NotSupportedArrayType_ThrowsNotSupportedException>b__1()
    System.Threading.Tests.PeriodicTimerTests.PeriodicTimer_NoActiveOperations_TimerNotRooted [SKIP]

What is really strange is that due to this failure, other tests that were passing so far started to fail as well:

    System.Tests.TypeTests.IsSZArray_TrueForSZArrayTypes [FAIL]
      System.TypeLoadException : Error getting the interfaces of System.Void[] due to Error Loading class assembly:/root/helix/work/correlation/shared/Microsoft.NETCore.App/9.0.0/System.Private.CoreLib.dll type:IList`1 member:(null)
      Stack Trace:
        /_/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs(1900,0): at System.RuntimeType.MakeArrayType()
        /_/src/libraries/System.Runtime/tests/System/Type/TypeTests.cs(613,0): at System.Tests.TypeTests.<>c.<IsSZArray_TrueForSZArrayTypes>b__36_0(Type nonArrayBaseType)
        /_/src/libraries/System.Linq/src/System/Linq/Select.cs(238,0): at System.Linq.Enumerable.SelectListIterator`2[[System.Type, System.Private.CoreLib, Version=9.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Type, System.Private.CoreLib, Version=9.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MoveNext()
        /_/src/libraries/System.Runtime/tests/System/Type/TypeTests.cs(613,0): at System.Tests.TypeTests.IsSZArray_TrueForSZArrayTypes()
        /_/src/mono/System.Private.CoreLib/src/System/Reflection/MethodBaseInvoker.Mono.cs(22,0): at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
        /_/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodBaseInvoker.cs(57,0): at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
    System.Threading.Tests.PeriodicTimerTests.PeriodicTimer_ActiveOperations_TimerRooted [SKIP]

I was not able to repro it with a standalone app:

using System.Reflection;

namespace ArrayOfVoid
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine($"IsMono: {Type.GetType("Mono.RuntimeStructs") != null}");

            Console.WriteLine(typeof(void).MakeArrayType().IsArray);
            Console.WriteLine(typeof(void).MakeArrayType().MakeArrayType().IsArray);

            Console.WriteLine(typeof(void).MakeArrayType().GetElementType()!.IsArray);
            Console.WriteLine(typeof(void).MakeArrayType().MakeArrayType().GetElementType()!.IsArray);
            Console.WriteLine(typeof(void).MakeArrayType().MakeArrayType().GetElementType()!.GetElementType()!.IsArray);
        }
    }
}
dotnet publish -c Release -r win-x64 --self-contained /p:UseMonoRuntime=true
.\bin\Release\net8.0\win-x64\publish\ArrayOfVoid.exe
IsMono: True
True
True
False
True
False

This test is trying to create an array of arrays of void, I suspect that this is somehow triggering some edge case.

BTW some of the tests are marked with [ActiveIssue("https://github.com/dotnet/runtime/issues/52072" despite the fact that #52072 has been closed (cc @mdh1418)

@adamsitnik adamsitnik added area-System.Runtime runtime-mono specific to the Mono runtime labels Oct 27, 2023
@ghost
Copy link

ghost commented Oct 27, 2023

Tagging subscribers to this area: @dotnet/area-system-runtime
See info in area-owners.md if you want to be subscribed.

Issue Details

In #88620 I've added a very simple code that performs following checks:

private static void ValidateArrayType(Type arrayType)
{
    if (!arrayType.IsArray)
        ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_HasToBeArrayClass, ExceptionArgument.arrayType);

    ValidateElementType(arrayType.GetElementType()!);
}

private static void ValidateElementType(Type elementType)
{
    while (elementType.IsArray)
    {
        elementType = elementType.GetElementType()!;
    }

    if (elementType.IsByRef || elementType.IsByRefLike)
        ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ByRefLikeArray);
    if (elementType == typeof(void))
        ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_VoidArray);
    if (elementType.ContainsGenericParameters)
        ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_OpenType);
}

The tests pass on CLR and NativeAOT, but fail on Mono:

    System.Tests.ArrayTests.CreateInstanceFromArrayType_NotSupportedArrayType_ThrowsNotSupportedException(elementType: typeof(System.Void)) [FAIL]
      Assert.Throws() Failure: Exception type was not an exact match
      Expected: typeof(System.NotSupportedException)
      Actual:   typeof(System.TypeLoadException)
      ---- System.TypeLoadException : Could not load array element class, due to: Error getting the interfaces of System.Void[] due to Error Loading class assembly:/root/helix/work/correlation/shared/Microsoft.NETCore.App/9.0.0/System.Private.CoreLib.dll type:IList`1 member:(null) assembly:/root/helix/work/correlation/shared/Microsoft.NETCore.App/9.0.0/System.Private.CoreLib.dll type:Void[] member:(null)
      Stack Trace:
        /_/src/libraries/System.Runtime/tests/System/ArrayTests.cs(1957,0): at System.Tests.ArrayTests.CreateInstanceFromArrayType_NotSupportedArrayType_ThrowsNotSupportedException(Type elementType)
        /_/src/mono/System.Private.CoreLib/src/System/Reflection/MethodBaseInvoker.Mono.cs(22,0): at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
        /_/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodBaseInvoker.cs(178,0): at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr)
        ----- Inner Stack Trace -----
        /_/src/mono/System.Private.CoreLib/src/System/RuntimeTypeHandle.cs(287,0): at System.RuntimeTypeHandle.GetElementType(RuntimeType type)
        /_/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs(96,0): at System.RuntimeType.GetElementType()
        /_/src/libraries/System.Private.CoreLib/src/System/Array.cs(338,0): at System.Array.ValidateArrayType(Type arrayType)
        /_/src/libraries/System.Private.CoreLib/src/System/Array.cs(261,0): at System.Array.CreateInstanceFromArrayType(Type arrayType, Int32[] lengths)
        /_/src/libraries/System.Runtime/tests/System/ArrayTests.cs(1957,0): at System.Tests.ArrayTests.<>c__DisplayClass90_0.<CreateInstanceFromArrayType_NotSupportedArrayType_ThrowsNotSupportedException>b__1()
    System.Threading.Tests.PeriodicTimerTests.PeriodicTimer_NoActiveOperations_TimerNotRooted [SKIP]

What is really strange is that due to this failure, other tests that were passing so far started to fail as well:

    System.Tests.TypeTests.IsSZArray_TrueForSZArrayTypes [FAIL]
      System.TypeLoadException : Error getting the interfaces of System.Void[] due to Error Loading class assembly:/root/helix/work/correlation/shared/Microsoft.NETCore.App/9.0.0/System.Private.CoreLib.dll type:IList`1 member:(null)
      Stack Trace:
        /_/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs(1900,0): at System.RuntimeType.MakeArrayType()
        /_/src/libraries/System.Runtime/tests/System/Type/TypeTests.cs(613,0): at System.Tests.TypeTests.<>c.<IsSZArray_TrueForSZArrayTypes>b__36_0(Type nonArrayBaseType)
        /_/src/libraries/System.Linq/src/System/Linq/Select.cs(238,0): at System.Linq.Enumerable.SelectListIterator`2[[System.Type, System.Private.CoreLib, Version=9.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Type, System.Private.CoreLib, Version=9.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MoveNext()
        /_/src/libraries/System.Runtime/tests/System/Type/TypeTests.cs(613,0): at System.Tests.TypeTests.IsSZArray_TrueForSZArrayTypes()
        /_/src/mono/System.Private.CoreLib/src/System/Reflection/MethodBaseInvoker.Mono.cs(22,0): at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
        /_/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodBaseInvoker.cs(57,0): at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
    System.Threading.Tests.PeriodicTimerTests.PeriodicTimer_ActiveOperations_TimerRooted [SKIP]

I was not able to repro it with a standalone app:

using System.Reflection;

namespace ArrayOfVoid
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine($"IsMono: {Type.GetType("Mono.RuntimeStructs") != null}");

            Console.WriteLine(typeof(void).MakeArrayType().IsArray);
            Console.WriteLine(typeof(void).MakeArrayType().MakeArrayType().IsArray);

            Console.WriteLine(typeof(void).MakeArrayType().GetElementType()!.IsArray);
            Console.WriteLine(typeof(void).MakeArrayType().MakeArrayType().GetElementType()!.IsArray);
            Console.WriteLine(typeof(void).MakeArrayType().MakeArrayType().GetElementType()!.GetElementType()!.IsArray);
        }
    }
}
dotnet publish -c Release -r win-x64 --self-contained /p:UseMonoRuntime=true
.\bin\Release\net8.0\win-x64\publish\ArrayOfVoid.exe
IsMono: True
True
True
False
True
False

This test is trying to create an array of arrays of void, I suspect that this is somehow triggering some edge case.

BTW some of the tests are marked with [ActiveIssue("https://github.com/dotnet/runtime/issues/52072" despite the fact that #52072 has been closed (cc @mdh1418)

Author: adamsitnik
Assignees: -
Labels:

area-System.Runtime, runtime-mono

Milestone: -

@ghost ghost added the untriaged New issue has not been triaged by the area owner label Oct 27, 2023
adamsitnik added a commit to AlexRadch/runtime that referenced this issue Oct 27, 2023
@marek-safar marek-safar added this to the 9.0.0 milestone Oct 27, 2023
@ghost ghost removed the untriaged New issue has not been triaged by the area owner label Oct 27, 2023
@marek-safar
Copy link
Contributor

/cc @vargaz

@vargaz
Copy link
Contributor

vargaz commented Oct 27, 2023

Will look into it. AFAIK, void[] is not a valid type, so some operations on it will cause type load exceptions, mono might throw them in different places than coreclr.

@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Nov 16, 2023
jkotas added a commit to jkotas/runtime that referenced this issue Nov 17, 2023
The CoreCLR type loader allowed creating arrays of System.Void. Many operations with these invalid array types failed, often in inscrutable ways. For example, GetInterfaces() call failed with type load exception of IEnumerable type. The exact failure modes are different between runtimes.

It is better to disallow creating these invalid array types in the first place, across all runtimes, to make the behavior robust and consistent.

Related to dotnet#88620

Fixes dotnet#94086
jkotas added a commit that referenced this issue Nov 17, 2023
The CoreCLR type loader allowed creating arrays of System.Void. Many operations with these invalid array types failed, often in inscrutable ways. For example, GetInterfaces() call failed with type load exception of IEnumerable type. The exact failure modes are different between runtimes.

It is better to disallow creating these invalid array types in the first place, across all runtimes, to make the behavior robust and consistent.

Related to #88620

Fixes #94086
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Nov 17, 2023
@github-actions github-actions bot locked and limited conversation to collaborators Dec 18, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Runtime runtime-mono specific to the Mono runtime
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants