diff --git a/src/mono/mono/mini/ir-emit.h b/src/mono/mono/mini/ir-emit.h index 937222f568c22e..9165de198f19d8 100644 --- a/src/mono/mono/mini/ir-emit.h +++ b/src/mono/mono/mini/ir-emit.h @@ -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)) { \ diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index 3ed3f1054830e3..9e67f9969e88da 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -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); } } diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_82535/Runtime_82535.cs b/src/tests/JIT/Regression/JitBlue/Runtime_82535/Runtime_82535.cs new file mode 100644 index 00000000000000..110ea1d0d802b1 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_82535/Runtime_82535.cs @@ -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; + } + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_82535/Runtime_82535.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_82535/Runtime_82535.csproj new file mode 100644 index 00000000000000..310a81f802b2e2 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_82535/Runtime_82535.csproj @@ -0,0 +1,11 @@ + + + Exe + True + true + + + + + + diff --git a/src/tests/issues.targets b/src/tests/issues.targets index faa84e07573118..1f8a6e84d3af50 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -66,6 +66,9 @@ https://github.com/dotnet/runtime/issues/78899 + + https://github.com/dotnet/runtime/pull/82663 +