Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Crash in Mono when calling default method on generic interface (DIM) due to uninitialized vtable slot #113958

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
penspanic opened this issue Mar 27, 2025 · 3 comments · May be fixed by #115306
Labels
area-Codegen-JIT-mono untriaged New issue has not been triaged by the area owner

Comments

@penspanic
Copy link

Description

When running a minimal test using a generic interface with default method implementations (DIM) on Mono (built from the dotnet/runtime repository), a crash occurs in mini-trampolines.c due to a NULL vtable slot during DIM invocation.

The crash happens intermittently, but is reproducible after a few repeated runs.

Reproduction Steps

  1. Replace the contents of runtime/src/mono/sample/HelloWorld/Program.cs with the following code:
using System;

namespace HelloWorld
{
    public interface IDIMCrashGeneric<T>
    {
        private bool NeededForCrash1() => false;
        private bool NeededForCrash2() => false;
        void TryCrash() { Console.WriteLine("Crash failed:IDIMCrashGeneric<T>"); }
    }

    public class DIMCrashGenericInt : IDIMCrashGeneric<int>
    {
        public void Run()
        {
            Console.WriteLine("[DIMCrashGenericInt:Run]Before DIM call");
            ((IDIMCrashGeneric<int>)this).TryCrash();
            Console.WriteLine("[DIMCrashGenericInt:Run]After DIM call");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var instance = new DIMCrashGenericInt();
            instance.Run();
        }
    }
}
  1. Then from the runtime directory, build and run the HelloWorld sample:
cd runtime/src/mono
make

Expected behavior

Program should print:

[DIMCrashGenericInt:Run]Before DIM call
Crash failed:IDIMCrashGeneric<T>
[DIMCrashGenericInt:Run]After DIM call

Actual behavior

Occasional crash with assertion:

* Assertion at mini-trampolines.c:705, condition `*vtable_slot_to_patch' not met

Full log and stacktrace:

geunhee.park@geunhee mono % make    
make run -C sample/HelloWorld
../../../../dotnet.sh publish \
	-c Debug \
	-r osx-arm64 \
	/p:SampleUseAOT=false \
        /p:SampleUseFullAOT=false \
	/p:SampleTrim=false \
	/p:MonoEnableLLVM=false \
	/p:StripILCode=false \
	/p:TrimmingEligibleMethodsOutputDirectory= \
	'/p:MibcProfilePath=""' \
	/bl

  Determining projects to restore...
  All projects are up-to-date for restore.
  HelloWorld -> /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/HelloWorld.dll
  HelloWorld -> /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/
DOTNET_DebugWriteToStdErr=1 \
	MONO_ENV_OPTIONS="" \
	../../../../artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/HelloWorld
[DIMCrashGenericInt:Run]Before DIM call
* Assertion at /Users/geunhee.park/dev/dotnet/runtime/src/mono/mono/mini/mini-trampolines.c:705, condition `*vtable_slot_to_patch' not met


=================================================================
	Native Crash Reporting
=================================================================
Got a SIGABRT while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries 
used by your application.
=================================================================

=================================================================
	Native stacktrace:
=================================================================
	0x105ffcd98 - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libcoreclr.dylib : dump_native_stacktrace
	0x105ffcce0 - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libcoreclr.dylib : mono_dump_native_crash_info
	0x105f48388 - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libcoreclr.dylib : mono_handle_native_crash
	0x105ffc420 - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libcoreclr.dylib : sigabrt_signal_handler
	0x197082de4 - /usr/lib/system/libsystem_platform.dylib : _sigtramp
	0x19704bf70 - /usr/lib/system/libsystem_pthread.dylib : pthread_kill
	0x196f58908 - /usr/lib/system/libsystem_c.dylib : abort
	0x106121008 - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libcoreclr.dylib : monoeg_assert_abort
	0x106135208 - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libcoreclr.dylib : mono_log_write_logfile
	0x106131fc8 - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libcoreclr.dylib : structured_log_adapter
	0x10612170c - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libcoreclr.dylib : monoeg_g_logstr
	0x106121348 - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libcoreclr.dylib : monoeg_g_logv_nofree
	0x106121438 - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libcoreclr.dylib : monoeg_assertion_message
	0x1061214b4 - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libcoreclr.dylib : mono_assertion_message_unreachable
	0x105f4e16c - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libcoreclr.dylib : common_call_trampoline
	0x105f4f6c4 - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libcoreclr.dylib : mono_vcall_trampoline
	0x10507d4ec - Unknown
	0x105167908 - Unknown
	0x105167618 - Unknown
	0x105167770 - Unknown
	0x105e2f8b0 - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libcoreclr.dylib : mono_jit_runtime_invoke
	0x10621ae14 - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libcoreclr.dylib : do_runtime_invoke
	0x106214bfc - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libcoreclr.dylib : mono_runtime_invoke_checked
	0x10622078c - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libcoreclr.dylib : do_exec_main_checked
	0x10621ed20 - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libcoreclr.dylib : mono_runtime_exec_main_checked
	0x10621ed74 - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libcoreclr.dylib : mono_runtime_run_main_checked
	0x105eeac9c - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libcoreclr.dylib : mono_jit_exec_internal
	0x105eeaab0 - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libcoreclr.dylib : mono_jit_exec
	0x105eef47c - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libcoreclr.dylib : main_thread_handler
	0x105eedddc - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libcoreclr.dylib : mono_main
	0x105fbf6d0 - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libcoreclr.dylib : monovm_execute_assembly
	0x105e16cd4 - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libcoreclr.dylib : coreclr_execute_assembly
	0x105607dc8 - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libhostpolicy.dylib : _ZN9coreclr_t16execute_assemblyEiPPKcS1_Pj
	0x10564d90c - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libhostpolicy.dylib : _Z19run_app_for_contextRK20hostpolicy_context_tiPPKc
	0x10564db90 - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libhostpolicy.dylib : _Z7run_appiPPKc
	0x10564e740 - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libhostpolicy.dylib : corehost_main
	0x1051ec60c - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libhostfxr.dylib : _ZL11execute_appRKNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEEP15corehost_init_tiPPKc
	0x1051e96b4 - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libhostfxr.dylib : _ZN12_GLOBAL__N_123read_config_and_executeERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEERK19host_startup_info_tS8_RKNS0_13unordered_mapI13known_optionsNS0_6vectorIS6_NS4_IS6_EEEE18known_options_hashNS0_8equal_toISD_EENS4_INS0_4pairIKS
	0x1051e6a20 - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libhostfxr.dylib : _ZN10fx_muxer_t24handle_exec_host_commandERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEERK19host_startup_info_tS8_RKNS0_13unordered_mapI13known_optionsNS0_6vectorIS6_NS4_IS6_EEEE18known_options_hashNS0_8equal_toISD_EENS4_INS0_4pairIKSD
	0x1051e5e20 - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libhostfxr.dylib : _ZN10fx_muxer_t7executeENSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEiPPKcRK19host_startup_info_tPciPi
	0x1051d55d0 - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/libhostfxr.dylib : hostfxr_main_startupinfo
	0x104fe6eb8 - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/HelloWorld : _Z9exe_startiPPKc
	0x104fe7300 - /Users/geunhee.park/dev/dotnet/runtime/artifacts/bin/HelloWorld/arm64/Debug/osx-arm64/publish/HelloWorld : main
	0x196ccc274 - /usr/lib/dyld : start

=================================================================
	External Debugger Dump:
=================================================================

=================================================================
	Basic Fault Address Reporting
=================================================================
Memory around native instruction pointer (0x197013720):0x197013710  ff 0f 5f d6 c0 03 5f d6 10 29 80 d2 01 10 00 d4  .._..._..)......
0x197013720  03 01 00 54 7f 23 03 d5 fd 7b bf a9 fd 03 00 91  ...T.#...{......
0x197013730  67 e0 ff 97 bf 03 00 91 fd 7b c1 a8 ff 0f 5f d6  g........{...._.
0x197013740  c0 03 5f d6 70 0a 80 d2 01 10 00 d4 03 01 00 54  .._.p..........T

=================================================================
	Managed Stacktrace:
=================================================================
	  at <unknown> <0xffffffff>
	  at HelloWorld.DIMCrashGenericInt:Run <0x00057>
	  at HelloWorld.Program:Main <0x0004f>
	  at <Module>:runtime_invoke_void_object <0x00087>
=================================================================
make[1]: *** [run] Abort trap: 6
make: *** [run-sample] Error 2

Regression?

Unknown. Reproduced on main of dotnet/runtime as of March 2025(ead91c5).

Known Workarounds

  • Removing one of the two private default methods in the interface avoids the crash.
// ...
public interface IDIMCrashGeneric<T>
{
        // Like this
        // private bool NeededForCrash1() => false;
        private bool NeededForCrash2() => false;
        void TryCrash() { Console.WriteLine("Crash failed:IDIMCrashGeneric<T>"); }
}
// ...
  • Running with CoreCLR (dotnet run) instead of Mono does not crash.

Configuration

  • .NET Version: 10.0.0-dev (main, ead91c5)
  • Runtime: Mono (from dotnet/runtime/src/mono)
  • OS: macOS 15.3.1
  • Architecture: ARM64 (Apple M1 Pro)
  • Intermittent repro, but consistently reproducible with repeated runs

Other information

@dotnet-issue-labeler dotnet-issue-labeler bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Mar 27, 2025
@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label Mar 27, 2025
@teo-tsirpanis teo-tsirpanis added area-Codegen-JIT-mono and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Mar 27, 2025
Copy link
Contributor

Tagging subscribers to this area: @steveisok, @vitek-karas
See info in area-owners.md if you want to be subscribed.

@lambdageek
Copy link
Member

lambdageek commented May 1, 2025

A couple observations:

  1. Repros in net8.0
  2. it's not deterministic. Running it in a loop, I get a crash about 80% of the time (osx-arm64). which is weird because there's no threading
  3. crash happens with other generic instantiations, not just int - object crashes too. but it does need to be generic, a non-generic DIM doesn't crash
  4. Doesn't seem to crash with the interpreter, so it's something about the trampolines, not about the DIM vtable layout

Probably there's a missing write barrier somewhere

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <UseMonoRuntime>true</UseMonoRuntime>
    <SelfContained>true</SelfContained>
  </PropertyGroup>

</Project>

@lambdageek
Copy link
Member

This feels very similar to #94437 - it feels like built_imt_slots is getting out of sync again and we end up looking at some unrelated memory instead of at the vtable. That could explain the non-determinism - if we are accessing some random memory past the vtable (because the vt_slot counter steps too far) it could sometimes be null and sometimes not, which would make this line return a "slot" that is really some random memory

vtable_slot = mini_resolve_imt_method (vt, vtable_slot, imt_method, &impl_method, &addr, &need_rgctx_tramp, &variant_iface, error);

and then we use that location as the slot to patch

vtable_slot_to_patch = vtable_slot;

and since it's not really the vtable but some unrelated memory, it sometimes has a NULL and sometimes a non-NULL.


I had started a follow-up PR to try and add some extra assertions to the IMT slot calculation, but I don't remember why i never finished - whether it didn't work or i just got pulled away to something else: e2f058c

lateralusX added a commit to lateralusX/runtime that referenced this issue May 5, 2025
In case of a generic interface, build_imt_slots calculate
the vt_slot to find the index in the vtable for the implementation.
Currently implementation assumed interface methods are either static
or virtual, but it's possible to have private/sealed methods that
won't end up as virtual. This is handled when building the vtable,
by not including these methods, but we didn't handle that scenario
when building the IMT slots, ending up with wrong vtable slot,
potentially outside of allocated memory.

Fixes dotnet#113958.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-Codegen-JIT-mono untriaged New issue has not been triaged by the area owner
Projects
None yet
3 participants