From 3816e04674acccc8120fb1680c3cf99eb388613d Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Sat, 18 Jul 2026 17:21:16 -0500 Subject: [PATCH] [wasm] Fix AOT + BlazorWebAssemblyLazyLoad startup crash When an app is published with AOT and uses BlazorWebAssemblyLazyLoad, the Mono runtime crashes during startup (appdomain.c assertion / interp.c NIY 'should not be reached'). Root cause: an AOT image hard-binds to every assembly it references when the image is loaded (see load_aot_module in aot-runtime.c, which eagerly calls load_image for all referenced images unless aot-lazy-assembly-load is set). A lazy-loaded assembly is not present at runtime startup, so any AOT image that references it is marked 'unusable because dependency is not found' and its methods fall back to the interpreter, which then hits an unsupported construct and aborts. Enable the runtime's 'aot-lazy-assembly-load' option automatically from the WebAssembly SDK when AOT is combined with BlazorWebAssemblyLazyLoad, so referenced lazy assemblies are only bound when they are actually loaded. Also add AOT + lazy-load regression coverage to LazyLoadingTests, which previously only exercised the interpreter (Debug) configuration. Fixes #125794 --- ...rosoft.NET.Sdk.WebAssembly.Browser.targets | 6 +++++ .../wasm/Wasm.Build.Tests/LazyLoadingTests.cs | 22 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets index 48360c01d7e993..68372ab269aa4d 100644 --- a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets +++ b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets @@ -202,6 +202,12 @@ Copyright (c) .NET Foundation. All rights reserved. <_WasmWebcilVersion Condition="'$(_WasmWebcilVersion)' == ''">0 <_BlazorWebAssemblyJiterpreter>$(BlazorWebAssemblyJiterpreter) <_BlazorWebAssemblyRuntimeOptions>$(BlazorWebAssemblyRuntimeOptions) + + <_BlazorWebAssemblyRuntimeOptions Condition="'$(RunAOTCompilation)' == 'true' and @(BlazorWebAssemblyLazyLoad->Count()) != 0 and !$(_BlazorWebAssemblyRuntimeOptions.Contains('--aot-lazy-assembly-load'))">$([System.String]::Concat('$(_BlazorWebAssemblyRuntimeOptions)', ' --aot-lazy-assembly-load').Trim()) <_WasmInlineBootConfig Condition="'$(_WasmInlineBootConfig)' == '' and '$(_TargetingNET100OrLater)' == 'true'">true <_WasmInlineBootConfig Condition="'$(_WasmInlineBootConfig)' == ''">false diff --git a/src/mono/wasm/Wasm.Build.Tests/LazyLoadingTests.cs b/src/mono/wasm/Wasm.Build.Tests/LazyLoadingTests.cs index 24d3f0ce5e199e..5332e5fc1e420a 100644 --- a/src/mono/wasm/Wasm.Build.Tests/LazyLoadingTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/LazyLoadingTests.cs @@ -73,6 +73,28 @@ public async Task LoadLazyAssemblyTwiceIsIdempotent() Assert.False(result.ConsoleOutput.Any(m => m.Contains("must be marked with 'BlazorWebAssemblyLazyLoad'")), "Reloading an already-loaded lazy assembly must not throw the 'must be marked' error"); } + [Fact] + [TestCategory("native-mono")] + public async Task LoadLazyAssemblyWithAOT() + { + // Regression coverage for https://github.com/dotnet/runtime/issues/125794: + // AOT combined with BlazorWebAssemblyLazyLoad must still initialize the runtime + // and lazily load assemblies at runtime. AOT is only supported when publishing + // in Release, so this exercises the publish + AOT + lazy-load combination that + // the Debug build/run tests above do not cover. + Configuration config = Configuration.Release; + ProjectInfo info = CopyTestAsset(config, aot: true, TestAsset.WasmBasicTestApp, "LazyLoadingTestsAOT"); + PublishProject(info, config, new PublishOptions(AOT: true, ExtraMSBuildArgs: "-p:TestLazyLoading=true")); + + RunResult result = await RunForPublishWithWebServer(new BrowserRunOptions( + config, + AOT: true, + TestScenario: "LazyLoadingTest" + )); + + Assert.True(result.TestOutput.Any(m => m.Contains("FirstName")), "The lazy loading test didn't emit expected message with JSON"); + } + [Fact] public async Task FailOnMissingLazyAssembly() {