Description
On arm64 platforms (macOS arm64, Linux arm64, and Windows arm64 confirmed), the JIT generates incorrect code when copying a readonly struct via a field-by-field copy constructor inside a class constructor. The bug causes struct fields to read garbage values instead of the actual source values.
This bug causes silent data corruption in production code. It was discovered in a real-world application where test results became incorrect after upgrading to .NET 10.
Reproduction Steps
using System.Runtime.CompilerServices;
public readonly struct Endpoint
{
public Endpoint(Endpoint e)
{
A = e.A;
B = e.B;
C = e.C;
}
public Endpoint(int a, int b, int c) { A = a; B = b; C = c; }
public int A { get; }
public int B { get; }
public int C { get; }
}
public sealed class Range
{
private readonly Endpoint m_start;
private readonly Endpoint m_end;
// Using AggressiveOptimization to force reproduction of the bug which would eventually occur when tiered compilation optimizes the constructor
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public Range(Endpoint start, Endpoint end)
{
m_start = new Endpoint(start); // Copy via copy constructor
m_end = new Endpoint(end); // Copy via copy constructor
}
public int Length => m_end.A - m_start.A;
}
public class Program
{
public static int Main()
{
const int expected = 5759;
for (int i = 0; i < 10000; i++)
{
var r = new Range(new Endpoint(100, 0, 0), new Endpoint(100 + expected, 0, 0));
if (r.Length != expected)
{
Console.WriteLine($"FAIL at iteration {i}: Length={r.Length} (expected {expected}), hex=0x{r.Length:X}");
return 1;
}
}
Console.WriteLine($"PASS: 10000 iterations, Length always = {expected}");
return 0;
}
}
Expected behavior
PASS: 10000 iterations, Length always = 5759
Actual behavior
FAIL at iteration 0: Length=-100 (expected 5759), hex=0xFFFFFF9C
The Length property returns a garbage value instead of 5759.
Regression?
This is a regression in .NET 10. The same code works correctly on .NET 8, .NET 9 and .NET 10 prior to RC1.
Known Workarounds
DOTNET_JitEnablePostorderLocalAssertionProp=0
Configuration
.NET version: .NET 10.0.5
OS: macOS 15 or 26
Architecture: ARM64
This impacts macOS, Linux and Windows ARM64 platforms: https://github.com/martinpotter/JitBugRepro/actions/runs/23853768346
Other information
This bug was introduced with bbe64d0. Prior to, or reverting, that commit, the bug is no longer reproducible.
Description
On arm64 platforms (macOS arm64, Linux arm64, and Windows arm64 confirmed), the JIT generates incorrect code when copying a readonly struct via a field-by-field copy constructor inside a class constructor. The bug causes struct fields to read garbage values instead of the actual source values.
This bug causes silent data corruption in production code. It was discovered in a real-world application where test results became incorrect after upgrading to .NET 10.
Reproduction Steps
Expected behavior
Actual behavior
The
Lengthproperty returns a garbage value instead of5759.Regression?
This is a regression in .NET 10. The same code works correctly on .NET 8, .NET 9 and .NET 10 prior to RC1.
Known Workarounds
Configuration
.NET version: .NET 10.0.5
OS: macOS 15 or 26
Architecture: ARM64
This impacts macOS, Linux and Windows ARM64 platforms: https://github.com/martinpotter/JitBugRepro/actions/runs/23853768346
Other information
This bug was introduced with bbe64d0. Prior to, or reverting, that commit, the bug is no longer reproducible.