Skip to content

Regression in v10 Preview 4 during a roll-forward from v9 causing System.TypeLoadException #61842

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

Closed
Junjun-zhao opened this issue Apr 16, 2025 · 10 comments
Assignees
Labels
area-blazor Includes: Blazor, Razor Components untriaged
Milestone

Comments

@Junjun-zhao
Copy link
Member

Junjun-zhao commented Apr 16, 2025

Description

When run the unit test of the 3rd party application with the latest .NET 10 build, it failed with error: System.TypeLoadException : Method 'InvokeNew' in type 'Bunit.JSInterop.BunitJSRuntime' from assembly 'bunit' does not have an implementation.

Reproduction Steps

App Repro Steps:

  1. Change the App\Blog1.LinkDotNet.Blog.UnitTests.runtimeconfig.json to let the app run against with dotnet-sdk-10.0.100-preview.4.25215.17.
    "frameworks": [
      {
        "name": "Microsoft.NETCore.App",
        "version": "10.0.0-preview.4.25211.19"
      },
      {
        "name": "Microsoft.AspNetCore.App",
        "version": "10.0.0-preview.4.25212.2"
      }
    ]
  1. Open cmd in App\Blog1.
  2. Run command: dotnet vstest LinkDotNet.Blog.UnitTests.dll

Expected Result:
All cases passed.

Actual Result:
Some cases failed with error:

System.TypeLoadException : Method 'InvokeNew' in type 'Bunit.JSInterop.BunitJSRuntime' from assembly 'bunit, Version=2.0.24.15694, Culture=neutral, PublicKeyToken=fe9c6306bcc1ce6f' does not have an implementation.
  Stack Trace:
     at Bunit.BunitJSInterop..ctor()
   at Bunit.BunitJSInterop..ctor()
   at Bunit.BunitContext..ctor() in /_/src/bunit/BunitContext.cs:line 30
   at LinkDotNet.Blog.UnitTests.Web.Features.ShowBlogPost.Components.PatreonTests..ctor()
   at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean wrapExceptions)

Minimal Repro Steps (Demo attached:Demo.zip):

  1. Create a default 9.0 ASP.NET Core Project and a default 9.0 xUnit Test Project. (The xUnit Test Project reference ASP.NET Core Project.)
  2. Install package bunit 2.0.36 in xUnit Test Project.
  3. Input the following code in UnitTest1.cs.
using Bunit;
namespace TestDemo
{
    public class UnitTest1 : BunitContext
    {
        [Fact]
        public void Test1()
        {
        }
    }
}
  1. Build the xUnit Test Project.
  2. Change the runtimeconfig.json file to let the app run against with dotnet-sdk-10.0.100-preview.4.25215.17.
    "frameworks": [
      {
        "name": "Microsoft.NETCore.App",
        "version": "10.0.0-preview.4.25211.19"
      },
      {
        "name": "Microsoft.AspNetCore.App",
        "version": "10.0.0-preview.4.25212.2"
      }
    ]
  1. Run Test1 with command : dotnet vstest TestDemo.dll.

Expected behavior

Test1 Passed.

Actual behavior

Test1 Failed with error:

Message: 
  System.TypeLoadException : Method 'InvokeNew' in type 'Bunit.JSInterop.BunitJSRuntime' from assembly 'bunit, Version=2.0.36.26408, Culture=neutral, PublicKeyToken=fe9c6306bcc1ce6f' does not have an implementation.
Stack Trace: 
  BunitJSInterop.ctor()
  BunitJSInterop.ctor()
  BunitContext.ctor()
  UnitTest1.ctor()
  RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean wrapExceptions)

Regression?

Yes

Verify Scenarios:
1). Windows 10 21H2 AMD64 + dotnet-sdk-9.0.104: Pass
2). Windows 10 21H2 AMD64 + dotnet-sdk-10.0.100-preview.3.25201.16: Pass
3). Windows 10 21H2 AMD64 + dotnet-sdk-10.0.100-preview.4.25211.22: Fail
4). Windows 10 21H2 AMD64 + dotnet-sdk-10.0.100-preview.4.25215.17: Fail

Known Workarounds

No response

Configuration

Application Name: Blog1
OS: Windows 10 21H2
CPU: X64
.NET Build Number: dotnet-sdk-10.0.100-preview.4.25215.17
App & Source Location checking at: https://devdiv.visualstudio.com/DevDiv/_workitems/edit/2449783
Github Link: https://github.com/linkdotnet/Blog

Other information

Findings:
In the demo, if xUnit Test Project does not reference ASP.NET Core Project, the error will not repro.

@dotnet-actwx-bot @dotnet/compat

@ghost ghost added the needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically label Apr 16, 2025
@teo-tsirpanis teo-tsirpanis removed the needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically label Apr 18, 2025
@steveharter steveharter self-assigned this Apr 21, 2025
@steveharter
Copy link

steveharter commented Apr 25, 2025

Manually changing the runtimeconfig.json files to reference newer major versions of the .net runtime and Asp.NET is likely unsupported in this case.

I was able to repro the TypeLoadException as shown above, but then inspected the bunit.dll's Bunit.JSInterop.BunitJSRuntime class and indeed doesn't have an InvokeNew method (only have Invoke() and InvokeAsync().

You'll need to work with bunit and\or LinkDotNet.Blog to see what their v10 support.

@steveharter steveharter closed this as not planned Won't fix, can't repro, duplicate, stale Apr 25, 2025
@WeiweiCaiAcpt
Copy link

WeiweiCaiAcpt commented Apr 27, 2025

@steveharter Thanks for help look into this issue.

Manually changing the runtimeconfig.json files to reference newer major versions of the .net runtime as Asp.NET is likely unsupported in this case.

We are the .NET AppCompat team. We are testing third-party applications by using DOTNET_ROLL_FORWARD_ON_NO_CANDIDATE_FX switch and the test machine only has the latest version of .NET nightly build installed. The goal is to identify any issues customers might come across with latest runtime and identify if it is an intentional breaking change.
This reported issue also occurs on the test machine that use roll forward switch.
We manually modify runtimeconfig.json in above repro steps to use the latest runtime and logging bugs because we consider user may have different version of .NET installed on the machine.

I was able to repro the TypeLoadException as shown above, but then inspected the bunit.dll's Bunit.JSInterop.BunitJSRuntime class and indeed doesn't have an InvokeNew method (only have Invoke() and InvokeAsync().

This issue is not repro in dotnet-sdk-10.0.100-preview.3.25201.16 but start failed from dotnet-sdk-10.0.100-preview.4.25211.22. Have there been any recent changes in .NET 10 Preview 4 that might have introduced this issue?

@steveharter
Copy link

steveharter commented Apr 28, 2025

We are the .NET AppCompat team. We are testing third-party applications by using DOTNET_ROLL_FORWARD_ON_NO_CANDIDATE_FX switch and the test machine only has the latest version of .NET nightly build installed. The goal is to identify any issues customers might come across with latest runtime and identify if it is an intentional breaking change.

I'll take another look at this. Thanks for the info.

@steveharter
Copy link

steveharter commented Apr 28, 2025

I don't see any System.Reflection.Emit use here, so moving location to runtime.

I repro'd this with 10.0.0-preview.5.25223.12.

The TypeLoadException exception appears to be thrown when calling CLRStub[MethodDescPrestub] after a call to create the instance via CORINFO_HELP_NEWSFAST().

The method "InvokeNew()" doesn't appear to have ever existed on Bunit.JSInterop.BunitJSRuntime so I don't know where that method name is coming from (perhaps the clr stub).

The managed call stack:

>	bunit.dll!Bunit.BunitContext.BunitContext() Line 30	C#
 	TestDemo.dll!TestDemo.UnitTest1.UnitTest1() Line 7	C#
 	System.Private.CoreLib.dll!System.RuntimeType.CreateInstanceImpl(System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder binder, object[] args, System.Globalization.CultureInfo culture)	Unknown
 	xunit.execution.dotnet.dll!ReflectionAbstractionExtensions.CreateTestClass.AnonymousMethod__0() Line 42	C#
 	xunit.execution.dotnet.dll!Xunit.Sdk.ExecutionTimer.Aggregate(System.Action action = {Method = {System.Reflection.RuntimeMethodInfo}}) Line 31	C#
 	xunit.execution.dotnet.dll!ReflectionAbstractionExtensions.CreateTestClass(Xunit.Abstractions.ITest test = {Xunit.Sdk.XunitTest}, System.Type testClassType = {Name = "UnitTest1" FullName = "TestDemo.UnitTest1"}, object[] constructorArguments = {object[0]}, Xunit.Sdk.IMessageBus messageBus = {Xunit.Sdk.MessageBus}, Xunit.Sdk.ExecutionTimer timer = {Xunit.Sdk.ExecutionTimer}, System.Threading.CancellationTokenSource cancellationTokenSource = IsCancellationRequested = false) Line 42	C#
 	xunit.execution.dotnet.dll!Xunit.Sdk.TestInvoker<Xunit.Sdk.IXunitTestCase>.CreateTestClass() Line 123	C#
 	xunit.execution.dotnet.dll!Xunit.Sdk.TestInvoker<Xunit.Sdk.IXunitTestCase>.RunAsync.AnonymousMethod__46_0() Line 167	C#
 	xunit.core.dll!Xunit.Sdk.ExceptionAggregator.RunAsync<decimal>(System.Func<System.Threading.Tasks.Task<decimal>> code = {Method = {System.Reflection.RuntimeMethodInfo}}) Line 107	C#
 	xunit.execution.dotnet.dll!Xunit.Sdk.TestInvoker<Xunit.Sdk.IXunitTestCase>.RunAsync() Line 163	C#

with some frames:

> System.Private.CoreLib.dll!System.RuntimeType.CreateInstanceImpl(System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder binder, object[] args, System.Globalization.CultureInfo culture) Line 3930 C#

        internal object? CreateInstanceImpl(
            BindingFlags bindingAttr, Binder? binder, object?[]? args, CultureInfo? culture)
        {
...
                if (invokeMethod.GetParametersAsSpan().Length == 0)
                {
                    if (args.Length != 0)
                    {
                        Debug.Assert((invokeMethod.CallingConvention & CallingConventions.VarArgs) ==
                                            CallingConventions.VarArgs);
                        throw new NotSupportedException(SR.NotSupported_CallToVarArg);
                    }

                    // fast path??
>                   instance = CreateInstanceLocal(wrapExceptions: wrapExceptions);
00007FFE9848FE96  mov         rcx,qword ptr [rbp+10h]  
00007FFE9848FE9A  mov         r8d,r15d  
00007FFE9848FE9D  mov         edx,1  
00007FFE9848FEA2  call        qword ptr [System.Tuple.Create[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]](System.__Canon, System.__Canon)+0685E28h (07FFE9902B908h)]  
                }
    public class UnitTest1 : BunitContext
    {
        public UnitTest1() : base()
00007FFE0919F800  push        rbp  
00007FFE0919F801  push        rdi  
00007FFE0919F802  push        rsi  
00007FFE0919F803  sub         rsp,20h  
00007FFE0919F807  mov         rbp,rsp  
00007FFE0919F80A  mov         qword ptr [rbp+40h],rcx  
00007FFE0919F80E  cmp         dword ptr [7FFE0906E940h],0  
00007FFE0919F815  je          TestDemo.UnitTest1..ctor()+01Ch (07FFE0919F81Ch)  
00007FFE0919F817  call        00007FFE683D7410  
00007FFE0919F81C  mov         rcx,qword ptr [rbp+40h]  
> 00007FFE0919F820  call        qword ptr [CLRStub[MethodDescPrestub]@00007FFE0912FF48 (07FFE0912FF48h)]  

and the last managed stack frame where this getter is being called:

--- /_/src/bunit/BunitContext.cs -----------------------------------------------

	/// <summary>
	/// Gets bUnits JSInterop, that allows setting up handlers for <see cref="IJSRuntime.InvokeAsync{TValue}(string, object[])"/> invocations
	/// that components under tests will issue during testing. It also makes it possible to verify that the invocations has happened as expected.
	/// </summary>
	public BunitJSInterop JSInterop { get; } = new BunitJSInterop();
 push        rbp  
 sub         rsp,80h  
 lea         rbp,[rsp+80h]  
 xor         eax,eax  
 mov         qword ptr [rbp-58h],rax  
 vxorps      xmm4,xmm4,xmm4  
 vmovdqu     ymmword ptr [rbp-50h],ymm4  
 vmovdqu     ymmword ptr [rbp-30h],ymm4  
 vmovdqa     xmmword ptr [rbp-10h],xmm4  
 mov         qword ptr [rbp+10h],rcx  
 cmp         dword ptr [7FFE44650728h],0  
 je          Bunit.BunitContext..ctor()+03Bh (07FFE445C90BBh)  
 call        00007FFEA3867410  
 mov         rcx,7FFE4478F9E8h  
 call        CORINFO_HELP_NEWSFAST (07FFEA36516E0h)  
 mov         qword ptr [rbp-8],rax  
 mov         rcx,qword ptr [rbp-8]  
>call        qword ptr [CLRStub[MethodDescPrestub]@00007FFE4472E088 (07FFE4472E088h)]  
 mov         rax,qword ptr [rbp+10h]  
 lea         rcx,[rax+10h]  
 mov         rdx,qword ptr [rbp-8]  
 call        CORINFO_HELP_ASSIGN_REF (07FFE43A20010h)  

and this appears to be native stack:

 	KernelBase.dll!RaiseException()	Unknown
 	clrjit.dll!Compiler::impImportBlockCode(BasicBlock * block=0x0000026a001ddaf8) Line 8761	C++
 	clrjit.dll!Compiler::impImportBlock(BasicBlock * block=0x0000026a001ddaf8) Line 11626	C++
 	clrjit.dll!Compiler::impImport() Line 12543	C++
 	clrjit.dll!Compiler::fgImport() Line 547	C++
 	clrjit.dll!Phase::Run() Line 62	C++
 	clrjit.dll!DoPhase(Compiler * _compiler, Phases _phase, PhaseStatus(Compiler::*)() _action) Line 144	C++
 	clrjit.dll!Compiler::compCompile(void * * methodCodePtr=0x000000eb194fb450, unsigned int * methodCodeSize=0x000000eb194fb6a8, JitFlags * compileFlags=0x000000eb194fb470) Line 4401	C++
 	clrjit.dll!Compiler::compCompileHelper(CORINFO_MODULE_STRUCT_ * classPtr=0x00007ffe43d5f970, ICorJitInfo * compHnd, CORINFO_METHOD_INFO * methodInfo=0x000000eb194fb860, void * * methodCodePtr=0x000000eb194fb450, unsigned int * methodCodeSize=0x000000eb194fb6a8, JitFlags * compileFlags=0x000000eb194fb470) Line 7200	C++
 	clrjit.dll!Compiler::compCompile(CORINFO_MODULE_STRUCT_ * classPtr=0x00007ffe43d5f970, void * * methodCodePtr=0x000000eb194fb450, unsigned int * methodCodeSize=0x000000eb194fb6a8, JitFlags * compileFlags=0x000000eb194fb470) Line 6377	C++
 	clrjit.dll!jitNativeCode(CORINFO_METHOD_STRUCT_ * methodHnd=0x00007ffe43f36f08, CORINFO_MODULE_STRUCT_ * classPtr=0x00007ffe43d5f970, ICorJitInfo * compHnd=0x000000eb194fb990, CORINFO_METHOD_INFO * methodInfo=0x000000eb194fb860, void * * methodCodePtr=0x000000eb194fb450, unsigned int * methodCodeSize=0x000000eb194fb6a8, JitFlags * compileFlags=0x000000eb194fb470, void * inlineInfoPtr) Line 7840	C++
 	clrjit.dll!CILJit::compileMethod(ICorJitInfo * compHnd=0x000000eb194fb990, CORINFO_METHOD_INFO * methodInfo=0x000000eb194fb860, unsigned int flags=794852816, unsigned char * * entryAddress=0x000000eb194fb6c0, unsigned int * nativeSizeOfCode=0x000000eb194fb6a8) Line 305	C++
 	[Managed to Native Transition]	
>	bunit.dll!Bunit.BunitContext.BunitContext() Line 30	C#

with last frame:
> clrjit.dll!Compiler::impImportBlockCode(BasicBlock * block=0x0000026a001ddaf8) Line 8761 C++

                _impResolveToken(CORINFO_TOKENKIND_NewObj);
00007FFEA2CDE72A  mov         r9d,202h  
00007FFEA2CDE730  lea         r8,[rbp-20h]  
00007FFEA2CDE734  mov         rdx,rbx  
00007FFEA2CDE737  mov         rcx,r15  
00007FFEA2CDE73A  and         esi,0FFFFFFEEh  
00007FFEA2CDE73D  call        Compiler::impResolveToken (07FFEA2CDB1DCh)  

                eeGetCallInfo(&resolvedToken, nullptr /* constraint typeRef*/,
00007FFEA2CDE742  mov         edx,1  

@steveharter steveharter removed their assignment Apr 28, 2025
@steveharter steveharter changed the title [dotnet-sdk-10.0.100-preview.4.25215.17] Blog1's unit tests run failed with an error: System.TypeLoadException : Method 'InvokeNew' in type 'Bunit.JSInterop.BunitJSRuntime' from assembly 'bunit' does not have an implementation. Regression in v10 Preview 4 during a roll-forward from v9 causing System.TypeLoadException Apr 29, 2025
@Junjun-zhao
Copy link
Member Author

Junjun-zhao commented May 6, 2025

@jeffhandley Could you please take a look at this issue and help triage it? In the meantime, could you please help confirm if this is a blocker for .NET 10 Preview 4? Thanks.

@jeffhandley
Copy link
Member

Calling in help from @jkotas or @dotnet/dotnet-coreclr on this, as this looks more like a jit/runtime topic than a libraries topic. I'm not aware of anything in the libraries side of things that could cause this failure.

@jkotas
Copy link
Member

jkotas commented May 8, 2025

Introduced by #61246. This change introduced InvokeNew method on IJSInProcessRuntime:

https://github.com/dotnet/aspnetcore/pull/61246/files#diff-b16b2af8a1eaff57999ca43f0cadd1f4f850bd81f41e899e39878f80198ec8efR31

Adding new method to an interface without a default implementation is a breaking change. Any existing type that implements the interface will fail to load since the new interface method will be missing implementation. It is exactly what's happening here: https://github.com/bUnit-dev/bUnit/blob/c98316921a63047407c6915ace115069fb72ba9d/src/bunit.web/JSInterop/Implementation/BunitJSRuntime.cs#L9 is the type in bunit package that implements the interface with the new method.

@jkotas jkotas transferred this issue from dotnet/runtime May 8, 2025
@jkotas jkotas added the area-blazor Includes: Blazor, Razor Components label May 8, 2025
@jkotas
Copy link
Member

jkotas commented May 8, 2025

@PriyaPurkayastha
Copy link

Per @javiercn "This is a dupe of https://github.com/dotnet/aspnetcore/issues/61621
Not a blocker, but we plan to change it on preview5 to provide a default interface implementation."

@javiercn please document this unintentional breaking change as a Preview 4 Known issue that will be addressed in Preview 5, so that customers are aware of it.

@CancanTang
Copy link

Verified this issue with dotnet-sdk-10.0.100-preview.5.25266.36, it has been fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-blazor Includes: Blazor, Razor Components untriaged
Projects
None yet
Development

No branches or pull requests

10 participants