-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Closed
Labels
area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMICLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
Milestone
Description
Description
A user of Npgsql ran into garbled nullable values on his M2.
The full context can be found here npgsql/npgsql#6058 (comment)
Reproduction Steps
using System;
using System.Runtime.CompilerServices;
// Necessary
[module: SkipLocalsInit]
static class Program
{
public static void Main()
{
var i = 0;
// Let the JIT tier up.
while (true)
{
var data = FaultyDefaultNullable<long?>();
var d = data.GetValueOrDefault();
// We need to dirty the stack and make sure this won't be optimized out by doing GC.Keepalive.
var iObject = (object)i;
var dataObject = (object?)data;
var dObject = (object?)d;
var hasValueObject = (object?)data.HasValue;
// Alternatively
// Console.WriteLine("{0}: `{1}` / {2}, `{3}`", i, data, d, data.HasValue);
if (d != 0)
{
Console.WriteLine($"Unexpected value: {d} / {d:X} / {d:b8}");
throw new Exception("We are here");
}
GC.KeepAlive(iObject);
GC.KeepAlive(dataObject);
GC.KeepAlive(dObject);
GC.KeepAlive(hasValueObject);
i++;
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
static T FaultyDefaultNullable<T>()
{
// When T is a Nullable<T> (and only in that case), we support returning null
if (default(T) is null && typeof(T).IsValueType)
return default!;
throw new InvalidOperationException("Not nullable");
}
[MethodImpl(MethodImplOptions.NoInlining)]
static T OkDefaultNullable<T>() => default!;
}
Expected behavior
OkDefaultNullable
; Assembly listing for method Program:OkDefaultNullable[System.Nullable`1[long]]():System.Nullable`1[long] (Tier1)
; Emitting BLENDED_CODE for generic ARM64 - Apple
; Tier1 code
; optimized code
; optimized using Synthesized PGO
; fp based frame
; partially interruptible
; with Synthesized PGO: fgCalledCount is 100
; No PGO data
G_M000_IG01: ;; offset=0x0000
stp fp, lr, [sp, #-0x10]!
mov fp, sp
G_M000_IG02: ;; offset=0x0008
mov w0, wzr
mov x1, xzr
G_M000_IG03: ;; offset=0x0010
ldp fp, lr, [sp], #0x10
ret lr
; Total bytes of code 24
Actual behavior
FaultyDefaultNullable
; Assembly listing for method Program:FaultyDefaultNullable[System.Nullable`1[long]]():System.Nullable`1[long] (Tier1)
; Emitting BLENDED_CODE for generic ARM64 - Apple
; Tier1 code
; optimized code
; optimized using Synthesized PGO
; fp based frame
; partially interruptible
; with Synthesized PGO: fgCalledCount is 100
; No PGO data
G_M000_IG01: ;; offset=0x0000
stp fp, lr, [sp, #-0x20]!
mov fp, sp
G_M000_IG02: ;; offset=0x0008
mov w0, wzr
ldr x1, [fp, #0x18]
G_M000_IG03: ;; offset=0x0010
ldp fp, lr, [sp], #0x20
ret lr
; Total bytes of code 24
Regression?
This code works in .NET 8.0, starts failing in 9.0 and onwards (also tested 10.0 preview 1)
Known Workarounds
Remove SkipLocalsInit from Npgsql
Configuration
No response
Other information
No response
EgorBo and PaulusParssinenPaulusParssinen
Metadata
Metadata
Assignees
Labels
area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMICLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI