You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
JIT crash: conditional branch to its own fall-through at the start of nested try regions (regression in .NET 9) #136505
A conditional branch whose target is its own fall-through instruction, where that instruction starts two nested try regions, crashes the process when the method is JIT-compiled. The IL is valid.
Reproduction Steps
usingSystem;usingSystem.Reflection.Emit;// static int M(int x): blt targets its own fall-through, which starts two nested try regions.varm=newDynamicMethod("M",typeof(int),new[]{typeof(int)});varil=m.GetILGenerator();varl=il.DefineLabel();il.Emit(OpCodes.Ldarg_0);il.Emit(OpCodes.Ldc_I4_1);il.Emit(OpCodes.Blt,l);if(args.Length>0)il.Emit(OpCodes.Br,l);// control: an unconditional branch after itil.MarkLabel(l);il.BeginExceptionBlock();// try ... catch (Exception)il.BeginExceptionBlock();// try ... finally, same startil.Emit(OpCodes.Nop);il.BeginFinallyBlock();il.EndExceptionBlock();il.BeginCatchBlock(typeof(Exception));il.Emit(OpCodes.Pop);il.EndExceptionBlock();il.Emit(OpCodes.Ldc_I4_0);il.Emit(OpCodes.Ret);varf=m.CreateDelegate<Func<int,int>>();Console.WriteLine($"{Environment.Version}: M(0) = {f(0)}, M(5) = {f(5)}");
dotnet run (no arguments) crashes; dotnet run -- control adds a br after the blt and runs. The same shape in a static method of an assembly crashes the same way under RuntimeHelpers.PrepareMethod.
Expected behavior
M(0) = 0, M(5) = 0, as on .NET 8.
Actual behavior
Runtime
Repro
Control
8.0.33
M(0) = 0, M(5) = 0
M(0) = 0, M(5) = 0
9.0.22
Fatal error. 0xC0000005
M(0) = 0, M(5) = 0
10.0.11
Internal CLR error. (0x80131506)
M(0) = 0, M(5) = 0
10.0.14
Fatal error. / Internal CLR error. (0x80131506)
M(0) = 0, M(5) = 0
Regression?
Yes: works on 8.0.33, crashes on 9.0.22, 10.0.11 and 10.0.14.
Known Workarounds
Remove the branch (a conditional branch to the next instruction is replaced by pops of its operands), or follow it with an unconditional br to the same target. With only one of the two try regions the method compiles.
Configuration
Windows 11 x64 (10.0.26200), SDK 10.0.403, x64 process.
Other information
The variant ldarg.0; conv.r8; ldc.r8 1.0; blt L crashed the same way on 10.0.11.
Activity
dotnet-policy-service commentedon Oct 27, 2026
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.
docs(dotnet): cite the upstream report of the JIT branch crash
JIT: Don't simplify degenerate conditional before import in fgReplace…