Description
Description
Referencing a ref struct with explicit layout, containing a ref struct, containing a struct, containing a value crashes the JIT in the importer phase when jitting the method containing that reference.
Reproduction Steps
using System.Runtime.InteropServices;
Console.WriteLine("Testing for crash.");
FailsToJit();
Console.WriteLine("Did not crash.");
static void FailsToJit()
{
// any reference (direct or indirect) to godot_variant will crash in during JIT import when resolving the type token
// loading a function pointer using the type, sizeof(), ... all crash in basically the same way
void Test(godot_variant arg) { }
Test(default);
}
[StructLayout(LayoutKind.Explicit)]
public ref struct godot_variant
{
[FieldOffset(0)] // offset doesn't matter
private godot_variant_data _data;
private ref struct godot_variant_data
{
private godot_variant_data_mem _mem;
public struct godot_variant_data_mem
{
private float _mem0; // also happens for int here
}
}
}
Expected behavior
Program runs to completion, printing two lines to console.
Actual behavior
The program crashes with the following output when trying to execute FailsToJit
.
Fatal error. Internal CLR error. (0x80131506)
at Program.<<Main>$>g__FailsToJit|0_0()
at Program.<Main>$(System.String[])
Native Backtrace:
> clrjit.dll!Compiler::lvaInitTypeRef() Line 280 C++
clrjit.dll!Compiler::compCompileHelper(CORINFO_MODULE_STRUCT_ * classPtr, ICorJitInfo * compHnd, CORINFO_METHOD_INFO * methodInfo, void * * methodCodePtr, unsigned int * methodCodeSize, JitFlags * compileFlags) Line 6509 C++
clrjit.dll!`Compiler::compCompile'[::M]::__Body::Run(Compiler::compCompile::__l2::__JITParam * __JITpParam) Line 5930 C++
clrjit.dll!Compiler::compCompile(CORINFO_MODULE_STRUCT_ * classPtr, void * * methodCodePtr, unsigned int * methodCodeSize, JitFlags * compileFlags) Line 5934 C++
clrjit.dll!``jitNativeCode'::`8'::__Body::Run'::`6'::__Body::Run(jitNativeCode::__l8::__Body::Run::__l5::__JITParam * __JITpParam) Line 7413 C++
clrjit.dll!`jitNativeCode'::`8'::__Body::Run(jitNativeCode::__l2::__JITParam * __JITpParam) Line 7416 C++
clrjit.dll!jitNativeCode(CORINFO_METHOD_STRUCT_ * methodHnd, CORINFO_MODULE_STRUCT_ * classPtr, ICorJitInfo * compHnd, CORINFO_METHOD_INFO * methodInfo, void * * methodCodePtr, unsigned int * methodCodeSize, JitFlags * compileFlags, void * inlineInfoPtr) Line 7440 C++
clrjit.dll!CILJit::compileMethod(ICorJitInfo * compHnd, CORINFO_METHOD_INFO * methodInfo, unsigned int flags, unsigned char * * entryAddress, unsigned int * nativeSizeOfCode) Line 261 C++
[Managed to Native Transition]
test.dll!Program.<Main>$(string[] args) Line 5 C#
[Native to Managed Transition]
[Inline Frame] hostpolicy.dll!coreclr_t::execute_assembly(int) Line 89 C++
hostpolicy.dll!run_app_for_context(const hostpolicy_context_t & context, int argc, const wchar_t * * argv) Line 255 C++
hostpolicy.dll!run_app(const int argc, const wchar_t * * argv) Line 284 C++
hostpolicy.dll!corehost_main(const int argc, const wchar_t * * argv) Line 430 C++
hostfxr.dll!execute_app(const std::wstring & impl_dll_dir, corehost_init_t * init, const int argc, const wchar_t * * argv) Line 146 C++
hostfxr.dll!`anonymous namespace'::read_config_and_execute(const std::wstring & host_command, const host_startup_info_t & host_info, const std::wstring & app_candidate, const std::unordered_map<enum known_options,std::vector<std::wstring,std::allocator<std::wstring>>,known_options_hash,std::equal_to<enum known_options>,std::allocator<std::pair<enum known_options const ,std::vector<std::wstring,std::allocator<std::wstring>>>>> & opts, int new_argc, const wchar_t * * new_argv, host_mode_t mode, const bool is_sdk_command, wchar_t * out_buffer, int buffer_size, int * required_buffer_size) Line 533 C++
hostfxr.dll!fx_muxer_t::handle_exec_host_command(const std::wstring & host_command, const host_startup_info_t & host_info, const std::wstring & app_candidate, const std::unordered_map<enum known_options,std::vector<std::wstring,std::allocator<std::wstring>>,known_options_hash,std::equal_to<enum known_options>,std::allocator<std::pair<enum known_options const ,std::vector<std::wstring,std::allocator<std::wstring>>>>> & opts, int argc, const wchar_t * * argv, int argoff, host_mode_t mode, const bool is_sdk_command, wchar_t * result_buffer, int buffer_size, int * required_buffer_size) Line 1018 C++
hostfxr.dll!fx_muxer_t::execute(const std::wstring host_command, const int argc, const wchar_t * * argv, const host_startup_info_t & host_info, wchar_t * result_buffer, int buffer_size, int * required_buffer_size) Line 579 C++
hostfxr.dll!hostfxr_main_startupinfo(const int argc, const wchar_t * * argv, const wchar_t * host_path, const wchar_t * dotnet_root, const wchar_t * app_path) Line 61 C++
test.exe!exe_start(const int argc, const wchar_t * * argv) Line 251 C++
test.exe!wmain(const int argc, const wchar_t * * argv) Line 322 C++
[Inline Frame] test.exe!invoke_main() Line 90 C++
test.exe!__scrt_common_main_seh() Line 288 C++
kernel32.dll!BaseThreadInitThunk�() Unknown
ntdll.dll!RtlUserThreadStart�() Unknown
Native debugging message:
Exception thrown: read access violation.
pSeries was 0x7FF7DB2478D8.
It varies depending on how the type is used, but it always ends at a call info.compCompHnd->xxx()
with a type token as one of the arguments.
I think execution should continue in coreclr.dll
at this point, but i am unable to get visual studio to step into that call, or to execute the program with a debug build of coreclr
Regression?
Yes, when changing the target framework to net6.0 the same code does not crash and executes successfully.
Known Workarounds
Removing about anything from the MRP makes the crash go away.
Configuration
On Windows 10 x64 versions:
.NET 7.0.2 - d099f07
.NET 7.0.0 - d037e07
On Linux Ubuntu 22.04.1 x64 version
.NET 7.0.2 - d037e07
Other information
No response