Repository navigation
Invalid IL produced by unreachable code blocks optimization #86304
Description
Activity
- addedarea-Tools-ILLink.NET linker development as well as trimming analyzers.NET linker development as well as trimming analyzers
on May 16, 2023 - ghost addeduntriagedNew issue has not been triaged by the area ownerNew issue has not been triaged by the area owner
on May 16, 2023 I think I found a compiler bug... I played with the above sample and created this:
try { throw new Exception(); } catch when (IntPtr.Size == 8 ? throw new Exception() : throw new Exception()) { Console.WriteLine(""); }
When compiled it produces IL like this:
.try { IL_0000: newobj instance void [System.Runtime]System.Exception::.ctor() IL_0005: throw } // end .try IL_0006: pop IL_0007: call int32 [System.Runtime]System.IntPtr::get_Size() IL_000c: ldc.i4.8 IL_000d: pop IL_000e: pop IL_000f: newobj instance void [System.Runtime]System.Exception::.ctor() IL_0014: throwIt's a try block with no handlers.
Trying to run this on CoreCLR produces:
System.InvalidProgramException: Common Language Runtime detected an invalid program.Trying to trim this crashes Cecil:
Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object. at Mono.Cecil.Cil.CodeReader.ReadExceptionHandlers(Int32 count, Func`1 read_entry, Func`1 read_length) at Mono.Cecil.Cil.CodeReader.ReadSmallSection() at Mono.Cecil.Cil.CodeReader.ReadSection() at Mono.Cecil.Cil.CodeReader.ReadFatMethod()NativeAOT actually handles this the best and prints out:
ILC: Method '[FilterBlockRemoval]Repro.Test()' will always throw because: Invalid IL or CLR metadata
(and then fails withInvalidProgramExceptionat runtime).Heh, cursed pattern.
There is a handler, but it's bogus (need to go to and uncheck View -> Expand try/catch in ILDasm UI):
.method private hidebysig static void '<Main>$'(string[] args) cil managed { .entrypoint // Code size 28 (0x1c) .maxstack 2 .locals init (bool V_0) IL_0000: nop IL_0001: newobj instance void [System.Runtime]System.Exception::.ctor() IL_0006: throw IL_0007: pop IL_0008: call int32 [System.Runtime]System.IntPtr::get_Size() IL_000d: ldc.i4.8 IL_000e: beq.s IL_0016 IL_0010: newobj instance void [System.Runtime]System.Exception::.ctor() IL_0015: throw IL_0016: newobj instance void [System.Runtime]System.Exception::.ctor() IL_001b: throw IL_001c: // Exception count 1 .try IL_0000 to IL_0007 filter IL_0007 handler IL_0002 to IL_001c } // end of method Program::'<Main>$'Will you do the honors in the Roslyn repo?
Hmm - somebody already did: dotnet/roslyn#67494
Reacted by Michal Strehovský- added 2 commits that reference this issue
on May 17, 2023 @vitek-karas can we close this?
Yes.
- ghost removeduntriagedNew issue has not been triaged by the area ownerNew issue has not been triaged by the area owner
on May 30, 2023 - ghost locked as resolved and limited conversation to collaborators
on Jun 29, 2023
IL Linker tries to remove unreachable basic blocks from exception filter blocks, but may strip the
endfilterinstruction in the process, making the IL invalid.Ran into this in the CoreCLR Pri0 test suite because Native AOT also imported this bug. The CoreCLR test is in IL but it can be reached with C# - this is the simplest way to reach it (pardon the nonsensical code, didn't want to think about this much):