From ad6fd4fa0d34bf2f7efd489a73d049f3b4a6be71 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 29 Nov 2025 21:08:42 +0000 Subject: [PATCH] Fix IndexOutOfRangeException in ILVerify for invalid exception handler offsets Co-authored-by: agocke <515774+agocke@users.noreply.github.com> Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../tools/Common/TypeSystem/IL/ILImporter.cs | 36 +++++++++++-- .../ILTests/ExceptionRegionTests.il | 50 +++++++++++++++++++ .../ILTests/ExceptionRegionTests.ilproj | 1 + .../tools/ILVerification/ILImporter.Verify.cs | 10 +++- src/coreclr/tools/ILVerification/Strings.resx | 3 ++ .../tools/ILVerification/VerifierError.cs | 4 +- .../IL/ILImporter.Scanner.cs | 5 ++ 7 files changed, 101 insertions(+), 8 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/IL/ILImporter.cs b/src/coreclr/tools/Common/TypeSystem/IL/ILImporter.cs index 74da13d94a398e..8da2e0afc67963 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/ILImporter.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/ILImporter.cs @@ -276,10 +276,40 @@ private void FindEHTargets() { var r = _exceptionRegions[i]; - CreateBasicBlock(r.ILRegion.TryOffset).TryStart = true; + // Check try region bounds (avoiding integer overflow) + if ((uint)r.ILRegion.TryOffset >= (uint)_basicBlocks.Length || + (uint)r.ILRegion.TryLength > (uint)_basicBlocks.Length - (uint)r.ILRegion.TryOffset) + { + ReportInvalidExceptionRegion(); + } + else + { + CreateBasicBlock(r.ILRegion.TryOffset).TryStart = true; + } + + // Check filter region bounds (for filter exception handlers) if (r.ILRegion.Kind == ILExceptionRegionKind.Filter) - CreateBasicBlock(r.ILRegion.FilterOffset).FilterStart = true; - CreateBasicBlock(r.ILRegion.HandlerOffset).HandlerStart = true; + { + if ((uint)r.ILRegion.FilterOffset >= (uint)_basicBlocks.Length) + { + ReportInvalidExceptionRegion(); + } + else + { + CreateBasicBlock(r.ILRegion.FilterOffset).FilterStart = true; + } + } + + // Check handler region bounds (avoiding integer overflow) + if ((uint)r.ILRegion.HandlerOffset >= (uint)_basicBlocks.Length || + (uint)r.ILRegion.HandlerLength > (uint)_basicBlocks.Length - (uint)r.ILRegion.HandlerOffset) + { + ReportInvalidExceptionRegion(); + } + else + { + CreateBasicBlock(r.ILRegion.HandlerOffset).HandlerStart = true; + } } } diff --git a/src/coreclr/tools/ILVerification.Tests/ILTests/ExceptionRegionTests.il b/src/coreclr/tools/ILVerification.Tests/ILTests/ExceptionRegionTests.il index 874c4202a0e8a6..d5eb26afff0ae9 100644 --- a/src/coreclr/tools/ILVerification.Tests/ILTests/ExceptionRegionTests.il +++ b/src/coreclr/tools/ILVerification.Tests/ILTests/ExceptionRegionTests.il @@ -764,4 +764,54 @@ throw ret } + + .method public hidebysig instance void TryOffset.ExceedsCodeSize_Invalid_EHClauseOutOfRange() cil managed + { + .maxstack 1 + + ret + // Try region starts at offset 1000 which is beyond code size (code size is 1) + .try 1000 to 1001 catch [System.Runtime]System.Exception handler 0 to 1 + } + + .method public hidebysig instance void HandlerOffset.ExceedsCodeSize_Invalid_EHClauseOutOfRange() cil managed + { + .maxstack 1 + + ret + // Handler region starts at offset 1000 which is beyond code size (code size is 1) + .try 0 to 1 catch [System.Runtime]System.Exception handler 1000 to 1001 + } + + .method public hidebysig instance void FilterOffset.ExceedsCodeSize_Invalid_EHClauseOutOfRange() cil managed + { + .maxstack 1 + + ldc.i4.0 + endfilter + leave.s IL_0004 + IL_0004: ret + // Filter region starts at offset 1000 which is beyond code size (code size is 5) + .try 0 to 2 filter 1000 handler 2 to 4 + } + + .method public hidebysig instance void TryEndOffset.ExceedsCodeSize_Invalid_EHClauseOutOfRange() cil managed + { + .maxstack 1 + + nop + ret + // Try region ends at offset 1000 which is beyond code size (code size is 2) + .try 0 to 1000 catch [System.Runtime]System.Exception handler 1 to 2 + } + + .method public hidebysig instance void HandlerEndOffset.ExceedsCodeSize_Invalid_EHClauseOutOfRange() cil managed + { + .maxstack 1 + + nop + ret + // Handler region ends at offset 1000 which is beyond code size (code size is 2) + .try 0 to 1 catch [System.Runtime]System.Exception handler 1 to 1000 + } } diff --git a/src/coreclr/tools/ILVerification.Tests/ILTests/ExceptionRegionTests.ilproj b/src/coreclr/tools/ILVerification.Tests/ILTests/ExceptionRegionTests.ilproj index 356b4dcc778989..6918de85f055d5 100644 --- a/src/coreclr/tools/ILVerification.Tests/ILTests/ExceptionRegionTests.ilproj +++ b/src/coreclr/tools/ILVerification.Tests/ILTests/ExceptionRegionTests.ilproj @@ -1,6 +1,7 @@ $(MSBuildProjectName) + $(IlasmFlags) -ERR diff --git a/src/coreclr/tools/ILVerification/ILImporter.Verify.cs b/src/coreclr/tools/ILVerification/ILImporter.Verify.cs index 434d2ab7687b38..a8dd3c939b39f1 100644 --- a/src/coreclr/tools/ILVerification/ILImporter.Verify.cs +++ b/src/coreclr/tools/ILVerification/ILImporter.Verify.cs @@ -209,6 +209,9 @@ public ILImporter(MethodDesc method, MethodIL methodIL) public void Verify() { + // Check code size before any other processing + FatalCheck(_ilBytes.Length > 0, VerifierError.CodeSizeZero); + _instructionBoundaries = new bool[_ilBytes.Length]; FindBasicBlocks(); @@ -286,8 +289,6 @@ private void FindEnclosingExceptionRegions() /// private void InitialPass() { - FatalCheck(_ilBytes.Length > 0, VerifierError.CodeSizeZero); - _modifiesThisPtr = false; _validTargetOffsets = new bool[_ilBytes.Length]; @@ -2823,6 +2824,11 @@ void ReportInvalidInstruction(ILOpcode opcode) VerificationError(VerifierError.UnknownOpcode); } + void ReportInvalidExceptionRegion() + { + VerificationError(VerifierError.EHClauseOutOfRange); + } + // // Deprecated // diff --git a/src/coreclr/tools/ILVerification/Strings.resx b/src/coreclr/tools/ILVerification/Strings.resx index 9f26f996d62f55..02be5d1e00ff0c 100644 --- a/src/coreclr/tools/ILVerification/Strings.resx +++ b/src/coreclr/tools/ILVerification/Strings.resx @@ -297,6 +297,9 @@ Fall through end of the method without returning. + + Exception handling clause bounds outside code size. + Cannot construct an instance of abstract class. diff --git a/src/coreclr/tools/ILVerification/VerifierError.cs b/src/coreclr/tools/ILVerification/VerifierError.cs index 2d237aa9c5b083..bc4821fbedb7d4 100644 --- a/src/coreclr/tools/ILVerification/VerifierError.cs +++ b/src/coreclr/tools/ILVerification/VerifierError.cs @@ -32,9 +32,7 @@ public enum VerifierError MethodFallthrough, // Fall through end of the method without returning. //E_TRY_GTEQ_END "try start >= try end." - //E_TRYEND_GT_CS "try end > code size." //E_HND_GTEQ_END "handler start >= handler end." - //E_HNDEND_GT_CS "handler end > code size." //E_TRY_START "Try starts in the middle of an instruction." //E_HND_START "Handler starts in the middle of an instruction." //E_TRY_OVERLAP "Try block overlap with another block." @@ -44,7 +42,7 @@ public enum VerifierError //E_FIL_CONT_TRY "Filter contains try." //E_FIL_CONT_HND "Filter contains handler." //E_FIL_CONT_FIL "Nested filters." - //E_FIL_GTEQ_CS "filter >= code size." + EHClauseOutOfRange, // Exception handling clause bounds outside code size. FallthroughException, // Fallthrough the end of an exception block. FallthroughIntoHandler, // Fallthrough into an exception handler. FallthroughIntoFilter, // Fallthrough into an exception filter. diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs index cf1a92fef36a8c..359c93a3e47e27 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs @@ -1600,6 +1600,11 @@ private static void ReportInvalidInstruction(ILOpcode opcode) ThrowHelper.ThrowInvalidProgramException(); } + private static void ReportInvalidExceptionRegion() + { + ThrowHelper.ThrowInvalidProgramException(); + } + private static bool IsTypeGetTypeFromHandle(MethodDesc method) { if (method.IsIntrinsic && method.Name.SequenceEqual("GetTypeFromHandle"u8))