From 94d2ce0fcfc853a80aa918685324344f7bead8e4 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 1 Jun 2023 14:34:05 +0200 Subject: [PATCH] Fix crash when control flow reaches end of method. --- .../ILPrettyTestRunner.cs | 6 +++ .../TestCases/ILPretty/EmptyBodies.cs | 14 ++++++ .../TestCases/ILPretty/EmptyBodies.il | 45 +++++++++++++++++++ ICSharpCode.Decompiler/IL/ILReader.cs | 15 +++++-- 4 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 ICSharpCode.Decompiler.Tests/TestCases/ILPretty/EmptyBodies.cs create mode 100644 ICSharpCode.Decompiler.Tests/TestCases/ILPretty/EmptyBodies.il diff --git a/ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs b/ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs index 237bdd402..5338bb7c9 100644 --- a/ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs +++ b/ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs @@ -263,6 +263,12 @@ namespace ICSharpCode.Decompiler.Tests await Run(); } + [Test] + public async Task EmptyBodies() + { + await Run(); + } + async Task Run([CallerMemberName] string testName = null, DecompilerSettings settings = null, AssemblerOptions assemblerOptions = AssemblerOptions.Library) { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/EmptyBodies.cs b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/EmptyBodies.cs new file mode 100644 index 000000000..6945a1db1 --- /dev/null +++ b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/EmptyBodies.cs @@ -0,0 +1,14 @@ +internal class EmptyBodies +{ + public static void RetVoid() + { + } + public static int RetInt() + { + return (int)/*Error near IL_0001: Stack underflow*/; + } + public static void Nop() + { + /*Error: End of method reached without returning.*/; + } +} \ No newline at end of file diff --git a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/EmptyBodies.il b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/EmptyBodies.il new file mode 100644 index 000000000..bd14a188c --- /dev/null +++ b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/EmptyBodies.il @@ -0,0 +1,45 @@ +#define CORE_ASSEMBLY "System.Runtime" + +.assembly extern CORE_ASSEMBLY +{ + .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....: + .ver 4:0:0:0 +} + +.class private auto ansi beforefieldinit EmptyBodies + extends [CORE_ASSEMBLY]System.Object +{ + // I cannot test a truly empty body because the assembler will automatically add a ret instruction. + + .method public hidebysig static void RetVoid () cil managed + { + .maxstack 8 + ret + } + + .method public hidebysig static int32 RetInt () cil managed + { + .maxstack 8 + ret + } + + .method public hidebysig static void Nop () cil managed + { + .maxstack 8 + nop + } + + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x206e + // Code size 8 (0x8) + .maxstack 8 + + IL_0000: ldarg.0 + IL_0001: call instance void [System.Private.CoreLib]System.Object::.ctor() + IL_0006: nop + IL_0007: ret + } // end of method Example::.ctor + +} // end of class EmptyBodies diff --git a/ICSharpCode.Decompiler/IL/ILReader.cs b/ICSharpCode.Decompiler/IL/ILReader.cs index 89d0739ae..8b1072967 100644 --- a/ICSharpCode.Decompiler/IL/ILReader.cs +++ b/ICSharpCode.Decompiler/IL/ILReader.cs @@ -535,16 +535,25 @@ namespace ICSharpCode.Decompiler.IL if (!block.Block.HasFlag(InstructionFlags.EndPointUnreachable)) { // create fall through branch - MarkBranchTarget(reader.Offset, isFallThrough: true); + ILInstruction branch; + if (reader.RemainingBytes > 0) + { + MarkBranchTarget(reader.Offset, isFallThrough: true); + branch = new Branch(reader.Offset); + } + else + { + branch = new InvalidBranch("End of method reached without returning."); + } if (block.Block.Instructions.LastOrDefault() is SwitchInstruction switchInst && switchInst.Sections.Last().Body.MatchNop()) { // Instead of putting the default branch after the switch instruction - switchInst.Sections.Last().Body = new Branch(reader.Offset); + switchInst.Sections.Last().Body = branch; Debug.Assert(switchInst.HasFlag(InstructionFlags.EndPointUnreachable)); } else { - block.Block.Instructions.Add(new Branch(reader.Offset)); + block.Block.Instructions.Add(branch); } } }