Repro
using System;
using System.Runtime.CompilerServices;
struct Big { public object A, B, C, D, E; }
public class Program
{
static Big s_src;
static string s_log = "";
[MethodImpl(MethodImplOptions.NoInlining)]
static ref Big GetSrc() { s_log += "GetSrc;"; return ref s_src; }
[MethodImpl(MethodImplOptions.NoInlining)]
static int Index() { s_log += "Index;"; return 0; }
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
static void Test(ref Big dst) { Unsafe.Add(ref dst, Index()) = GetSrc(); }
public static int Main()
{
try { Test(ref Unsafe.NullRef<Big>()); }
catch (Exception e) { Console.WriteLine(e.GetType().Name); }
Console.WriteLine("log=[" + s_log + "]");
return 100;
}
}
Expected
NullReferenceException
log=[Index;GetSrc;]
Actual
NullReferenceException
log=[Index;]
Both sides of the assignment must be evaluated before the copy can fault, but the destination null
check runs as soon as the destination address is computed, so the call on the right-hand side is
skipped entirely. Reducing Big to three object fields (which no longer uses the bulk-copy helper)
prints the expected log=[Index;GetSrc;].
Platform
Windows x64, .NET 11 (dotnet/runtime main @ a0b86b1, Checked build), DOTNET_TieredCompilation=0.
No special CPU features. Also reproduces identically on the Release build.
Repro
Expected
Actual
Both sides of the assignment must be evaluated before the copy can fault, but the destination null
check runs as soon as the destination address is computed, so the call on the right-hand side is
skipped entirely. Reducing
Bigto threeobjectfields (which no longer uses the bulk-copy helper)prints the expected
log=[Index;GetSrc;].Platform
Windows x64, .NET 11 (dotnet/runtime main @ a0b86b1, Checked build),
DOTNET_TieredCompilation=0.No special CPU features. Also reproduces identically on the Release build.