Skip to content

Commit

Permalink
[mono][jit] Emit a null check when storing to valuetype fields. (dotn…
Browse files Browse the repository at this point in the history
…et#82663)

* [mono][jit] Emit a null check when storing to valuetype fields.

Fixes dotnet#82535.

* Add a test.

* Disable the test on coreclr.
  • Loading branch information
vargaz authored Apr 29, 2023
1 parent 231f85f commit 6bb5449
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 0 deletions.
7 changes: 7 additions & 0 deletions src/mono/mono/mini/ir-emit.h
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,13 @@ static int ccount = 0;
#define MONO_EMIT_NEW_IMPLICIT_EXCEPTION_LOAD_STORE(cfg) do { \
} while (0)

#define MONO_EMIT_EXPLICIT_NULL_CHECK(cfg, reg) do { \
cfg->flags |= MONO_CFG_HAS_CHECK_THIS; \
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, (reg), 0); \
MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException"); \
MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, reg); \
} while (0)

/* Emit an explicit null check which doesn't depend on SIGSEGV signal handling */
#define MONO_EMIT_NULL_CHECK(cfg, reg, out_of_page) do { \
if (cfg->explicit_null_checks || (out_of_page)) { \
Expand Down
4 changes: 4 additions & 0 deletions src/mono/mono/mini/method-to-ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -10026,6 +10026,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
store = mini_emit_storing_write_barrier (cfg, ptr, sp [1]);
} else {
if (MONO_TYPE_ISSTRUCT (field->type))
/* The decomposition might end up calling a copy/wbarrier function which doesn't do null checks */
MONO_EMIT_EXPLICIT_NULL_CHECK (cfg, sp [0]->dreg);

EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
}
}
Expand Down
131 changes: 131 additions & 0 deletions src/tests/JIT/Regression/JitBlue/Runtime_82535/Runtime_82535.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// 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.Runtime.CompilerServices;

public class Program
{
public Program()
{
}

static int Main(string[] args)
{
Foo currentFoo;

Bacon defaultBacon = new Bacon(-180, 180, true, false, 300f, 0.1f, 0.1f, "Foo", false);
currentFoo = new Foo();
try {
currentFoo.GetBar().m_Bacon = defaultBacon;
} catch (NullReferenceException) {
return 100;
}
return 101;
}
}

public class Foo
{
private Bar m_Bar;
public Bar GetBar()
{
return m_Bar;
}
}


public class Bar
{
public Bacon m_Bacon = new Bacon(-180, 180, true, false, 300f, 0.1f, 0.1f, "Foo", false);
}

public struct Bacon
{
public float Value;
public enum FooEnum
{
One,
Two
};

public FooEnum m_FooEnum;
public float m_f1;
public float m_f2;
public float m_f3;
public string m_s1;
public float m_f8;
public bool m_bool1;
public float m_f4;
public float m_f5;
public bool m_bool2;
public FooBar m_FooBar;

float m_f6;
float m_f7;
int m_i1;

public bool bool3 { get; set; }

public bool bool4 { get; set; }

public interface IFooInterface
{
float GetFooValue(int foo);
}

IFooInterface m_FooProvider;
int m_i2;

public Bacon(
float minValue, float maxValue, bool wrap, bool rangeLocked,
float maxSpeed, float accelTime, float decelTime,
string name, bool invert)
{
m_f4 = minValue;
m_f5 = maxValue;
m_bool2 = wrap;
bool3 = rangeLocked;

bool4 = false;
m_FooBar = new FooBar(false, 1, 2);

m_FooEnum = FooEnum.One;
m_f1 = maxSpeed;
m_f2 = accelTime;
m_f3 = decelTime;
Value = (minValue + maxValue) / 2;
m_s1 = name;
m_f8 = 0;
m_bool1 = invert;

m_f6 = 0f;
m_FooProvider = null;
m_i2 = 0;
m_f7 = 0;
m_i1 = 0;
}

public struct FooBar
{
public bool m_FooBar_bool1;
public float m_FooBar_f1;
public float m_FooBar_f2;

float m_FooBar_f3;
float m_FooBar_f4;
float m_FooBar_f5;
int m_FooBar_i1;
int m_FooBar_i2;

public FooBar(bool b1, float f1, float f2)
{
m_FooBar_bool1 = b1;
m_FooBar_f1 = f1;
m_FooBar_f2 = f2;
m_FooBar_f4 = 0;
m_FooBar_f5 = 0;
m_FooBar_i1 = m_FooBar_i2 = -1;
m_FooBar_f3 = 0;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<Optimize>True</Optimize>
<RequiresProcessIsolation>true</RequiresProcessIsolation>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildProjectName).cs" />
</ItemGroup>
</Project>

3 changes: 3 additions & 0 deletions src/tests/issues.targets
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@
<ExcludeList Include="$(XunitTestBinBase)/GC/Regressions/Github/Runtime_76219/Runtime_76219/*">
<Issue>https://github.com/dotnet/runtime/issues/78899</Issue>
</ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)/JIT/Regression/JitBlue/Runtime_82535/*">
<Issue>https://github.com/dotnet/runtime/pull/82663</Issue>
</ExcludeList>
</ItemGroup>

<!-- All Unix targets on all runtimes -->
Expand Down

0 comments on commit 6bb5449

Please sign in to comment.