If the next code will be built in the Release configuration, an exception will be thrown because the object summary is null. This affects only .NET Core 3.0 and later. There is no issue in .NET Core 1.0-2.2.
public struct Ptr<T>
where T: class
{
private T _value;
public Ptr(T value)
{
_value = value;
}
//[MethodImpl(MethodImplOptions.NoInlining)]
public T Release()
{
T tmp = _value;
_value = null;
return tmp;
}
}
public class TestClass
{
}
class Program
{
private static void Main(string[] args)
{
Ptr<TestClass> ptr = new Ptr<TestClass>(new TestClass());
bool res = false;
while (res)
{
}
TestClass summary = ptr.Release();
if (summary == null)
throw new Exception("JIT optimization failure");
Consume(summary);
Console.WriteLine("OK");
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void Consume(TestClass summary)
{
}
}
There are some ways to fix an issue under .NET Core 3.0:
- Disable optimization in the project settings.
- Remove empty while loop.
- Uncomment MethodImpl attribute on
Ptr.Release() method.
- Make Ptr non-generic class (or just make
private T _value; member of Ptr class of type object).
Disassembly of JITed code in .NET Core 3.1:
Ptr<TestClass> ptr = new Ptr<TestClass>(new TestClass());
00007FF7C9420F50 push rsi
00007FF7C9420F51 sub rsp,20h
bool res = false;
00007FF7C9420F55 mov rcx,7FF7C94A4170h
00007FF7C9420F5F call 00007FF828F36CB0
00007FF7C9420F64 mov rsi,rax
00007FF7C9420F67 mov rcx,rsi
00007FF7C9420F6A call 00007FF7C9414C10
00007FF7C9420F6F mov ecx,1
00007FF7C9420F74 mov rdx,7FF7C94BF788h
00007FF7C9420F7E call 00007FF8290605B0
00007FF7C9420F83 lea rcx,[rsi+10h]
00007FF7C9420F87 mov rdx,rax
00007FF7C9420F8A call 00007FF828F35DF0
throw new Exception("JIT optimization failure");
00007FF7C9420F8F mov rcx,rsi
00007FF7C9420F92 call 00007FF828EAB900
00007FF7C9420F97 int 3
Disassembly of JITed code in .NET Core 2.2:
Ptr<TestClass> ptr = new Ptr<TestClass>(new TestClass());
00007FF7C9401520 sub rsp,28h
00007FF7C9401524 mov rcx,7FF7C92E6708h
00007FF7C940152E call 00007FF828EEB3B0
00007FF7C9401533 mov rcx,rax
00007FF7C9401536 mov rax,rcx
{
}
TestClass summary = ptr.Release();
00007FF7C9401539 mov rcx,rax
00007FF7C940153C call 00007FF7C94010A0
Console.WriteLine("OK");
00007FF7C9401541 mov rcx,262B4E23068h
00007FF7C940154B mov rcx,qword ptr [rcx]
00007FF7C940154E call 00007FF7C9401398
00007FF7C9401553 nop
00007FF7C9401554 add rsp,28h
00007FF7C9401558 ret
The test project was attached:
JitOptimizationFailure.zip
category:correctness
theme:importer
skill-level:intermediate
cost:small
If the next code will be built in the Release configuration, an exception will be thrown because the object summary is null. This affects only .NET Core 3.0 and later. There is no issue in .NET Core 1.0-2.2.
There are some ways to fix an issue under .NET Core 3.0:
Ptr.Release()method.private T _value;member of Ptr class of typeobject).Disassembly of JITed code in .NET Core 3.1:
Disassembly of JITed code in .NET Core 2.2:
The test project was attached:
JitOptimizationFailure.zip
category:correctness
theme:importer
skill-level:intermediate
cost:small