Skip to content

[mono][interp] NIY assertion crash in WASM Hybrid AOT when GC finalizes native callback delegate #121959

@clairernovotny

Description

@clairernovotny

Description

When running a .NET 10 Uno Platform WebAssembly application with Hybrid AOT, the Mono interpreter crashes with a "NIY" (Not Implemented Yet) assertion failure. The crash occurs when the garbage collector finalizes an SKData object that has a native callback delegate, and the interpreter attempts to execute a method that wasn't included in the AOT profile.

Reproduction Steps

  1. Create an Uno Platform WebAssembly project targeting net10.0-browserwasm with Hybrid AOT enabled
  2. Add the following code to Program.cs:
using System.Runtime.InteropServices;
using SkiaSharp;

static async void TestSkia()
{
    var imageBytes = Marshal.AllocHGlobal(100);
    SKData.Create(imageBytes, 100, (_, _) =>
    {
        Console.WriteLine("SKData DISPOSED!");
        Marshal.FreeHGlobal(imageBytes);
    });
    
    // Force GC to trigger the crash faster
    while (true)
    {
        await Task.Delay(25);
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
}

static Program()
{
    TestSkia();
}
  1. Build and run the WASM application
  2. The crash occurs when GC collects the SKData object and invokes the release callback

Expected behavior

The application should run without crashing. Methods invoked during GC finalization should either be AOT compiled or gracefully fall back to interpretation.

Actual behavior

The Mono interpreter crashes with an assertion failure:

* Assertion at interp.c:4130, condition `<NIY>' not met, function:interp_exec_method, 
MONO interpreter: NIY encountered in method Microsoft.UI.Xaml.Controls.ListViewBase:get_DataFetchSize ()

Stack Trace

Assertion at interp.c:4130, condition `<NIY>' not met
function: interp_exec_method
MONO interpreter: NIY encountered in method Microsoft.UI.Xaml.Controls.ListViewBase:get_DataFetchSize ()

The crash appears to occur when:

  1. GC runs and finalizes an object with a native callback
  2. The callback delegate invokes interpreted code
  3. The interpreter encounters a method not in the AOT profile
  4. The interpreter hits an unimplemented opcode or calling convention and asserts

Configuration

  • .NET SDK: 10.0.100
  • Uno.Sdk: 6.4.31
  • Target Framework: net10.0-browserwasm
  • SkiaSharp: Latest compatible version
  • AOT Mode: Hybrid (partial AOT with interpreter fallback)
  • Browser: Tested in Chrome/Edge

Project Configuration

<PropertyGroup>
    <TargetFramework>net10.0-browserwasm</TargetFramework>
    <WasmShellMonoRuntimeExecutionMode>InterpreterAndAOT</WasmShellMonoRuntimeExecutionMode>
</PropertyGroup>

Analysis

The issue appears to be in the Mono interpreter's handling of method calls that weren't AOT compiled when those calls originate from:

  1. GC finalizer context
  2. Native-to-managed callback transitions
  3. Delegate invocations during collection

The "NIY" assertion suggests the interpreter encountered an unimplemented code path, possibly related to:

  • Calling convention mismatch between AOT and interpreted code
  • Missing interpreter implementation for certain opcodes used in the method
  • Thread/context issues when transitioning from native GC callbacks back to managed code

Workaround

Currently, no reliable workaround exists. Possible mitigations:

  • Ensure all methods that might be called during finalization are in the AOT profile
  • Avoid using native callbacks with finalizable objects in WASM Hybrid AOT scenarios

Additional Context

This is blocking production use of Uno Platform with SkiaSharp on WebAssembly with Hybrid AOT. The crash is non-deterministic but can be reliably triggered by forcing frequent GC collections.

/cc @pgovind @AaronRobinsonMSFT

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions