Skip to content

Commit

Permalink
[mono][interp] Fix GetType called on ptr constrained to Nullable` (#6…
Browse files Browse the repository at this point in the history
…1020)

* [interp] Fix GetType called on ptr constrained to Nullable`

We were statically optimizing this call to return the actual constrained class type, which is incorrect for nullables, because boxing of a nullable (as part of the constrained call) actually creates an object with the type of the nullable's value (or null if there is no value).

* Add test for GetType call on ptr constrained to nullable
  • Loading branch information
BrzVlad authored Nov 4, 2021
1 parent d216c7c commit c02a37c
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 3 deletions.
14 changes: 11 additions & 3 deletions src/mono/mono/mini/interp/transform.c
Original file line number Diff line number Diff line change
Expand Up @@ -2440,7 +2440,7 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas
if (!strcmp (tm, "InternalGetHashCode")) {
*op = MINT_INTRINS_GET_HASHCODE;
} else if (!strcmp (tm, "GetType")) {
if (constrained_class && m_class_is_valuetype (constrained_class)) {
if (constrained_class && m_class_is_valuetype (constrained_class) && !mono_class_is_nullable (constrained_class)) {
// If constrained_class is valuetype we already know its type.
// Resolve GetType to a constant so we can fold type comparisons
ERROR_DECL(error);
Expand All @@ -2457,8 +2457,16 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas
return TRUE;
} else {
if (constrained_class) {
// deref the managed pointer to get the object
interp_add_ins (td, MINT_LDIND_I);
if (mono_class_is_nullable (constrained_class)) {
// We can't determine the behavior here statically because we don't know if the
// nullable vt has a value or not. If it has a value, the result type is
// m_class_get_cast_class (constrained_class), otherwise GetType should throw NRE.
interp_add_ins (td, MINT_BOX_NULLABLE_PTR);
td->last_ins->data [0] = get_data_item_index (td, constrained_class);
} else {
// deref the managed pointer to get the object
interp_add_ins (td, MINT_LDIND_I);
}
td->sp--;
interp_ins_set_sreg (td->last_ins, td->sp [0].local);
push_simple_type (td, STACK_TYPE_O);
Expand Down
48 changes: 48 additions & 0 deletions src/tests/JIT/Directed/nullabletypes/gettype.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Linq;
using System.Collections.Generic;

class C<T>
{
public IEnumerable<T> Data { get; set; }

public C() { }

public bool Check()
{
return Data.ElementAt(0).GetType() == typeof(bool);
}
}

public class P
{
public static int Main()
{
C<bool?> c = new();

// Try a nullable with value
c.Data = new List<bool?> { true };
if(!c.Check())
return 666;

// Try a nullable without value. Should throw NRE
c.Data = new List<bool?> { new Nullable<bool>() };

bool thrown = false;
try
{
c.Check();
}
catch(NullReferenceException)
{
thrown = true;
}
if(!thrown)
return 667;
return 100;
}
}

13 changes: 13 additions & 0 deletions src/tests/JIT/Directed/nullabletypes/gettype_d.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<CLRTestPriority>1</CLRTestPriority>
</PropertyGroup>
<PropertyGroup>
<DebugType>Full</DebugType>
<Optimize>False</Optimize>
</PropertyGroup>
<ItemGroup>
<Compile Include="gettype.cs" />
</ItemGroup>
</Project>
13 changes: 13 additions & 0 deletions src/tests/JIT/Directed/nullabletypes/gettype_do.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<CLRTestPriority>1</CLRTestPriority>
</PropertyGroup>
<PropertyGroup>
<DebugType>Full</DebugType>
<Optimize>True</Optimize>
</PropertyGroup>
<ItemGroup>
<Compile Include="gettype.cs" />
</ItemGroup>
</Project>
13 changes: 13 additions & 0 deletions src/tests/JIT/Directed/nullabletypes/gettype_r.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<CLRTestPriority>1</CLRTestPriority>
</PropertyGroup>
<PropertyGroup>
<DebugType>None</DebugType>
<Optimize>False</Optimize>
</PropertyGroup>
<ItemGroup>
<Compile Include="gettype.cs" />
</ItemGroup>
</Project>
13 changes: 13 additions & 0 deletions src/tests/JIT/Directed/nullabletypes/gettype_ro.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<CLRTestPriority>1</CLRTestPriority>
</PropertyGroup>
<PropertyGroup>
<DebugType>None</DebugType>
<Optimize>True</Optimize>
</PropertyGroup>
<ItemGroup>
<Compile Include="gettype.cs" />
</ItemGroup>
</Project>

0 comments on commit c02a37c

Please sign in to comment.