From af6662ee6f9dd5b7352384343975d721670fee9e Mon Sep 17 00:00:00 2001 From: Marek Safar Date: Tue, 22 Nov 2022 13:55:15 +0100 Subject: [PATCH] Fix incorrect range comparison for switch operands (dotnet/linker#3128) Commit migrated from https://github.com/dotnet/linker/commit/659f2b6a6bbbe41ab6366ac6a06bf86af2ec56cd --- .../UnreachableBlocksOptimizer.cs | 2 +- .../ComplexConditionsOptimized.cs | 50 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/tools/illink/src/linker/Linker.Steps/UnreachableBlocksOptimizer.cs b/src/tools/illink/src/linker/Linker.Steps/UnreachableBlocksOptimizer.cs index 28eb66f1513bc..2d9097f975df4 100644 --- a/src/tools/illink/src/linker/Linker.Steps/UnreachableBlocksOptimizer.cs +++ b/src/tools/illink/src/linker/Linker.Steps/UnreachableBlocksOptimizer.cs @@ -617,7 +617,7 @@ void RewriteCondition (int index, Instruction instr, int operand) case Code.Switch: var targets = (Instruction[]) instr.Operand; - if (operand <= targets.Length) { + if (operand < targets.Length) { // It does not need to be conditional but existing logic in BodySweeper would // need to be updated to deal with 1->2 instruction replacement RewriteConditionTo (index, Instruction.Create (operand == 0 ? OpCodes.Brfalse : OpCodes.Brtrue, targets[operand])); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/UnreachableBlock/ComplexConditionsOptimized.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/UnreachableBlock/ComplexConditionsOptimized.cs index 1161e757644b3..951243ab458d8 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/UnreachableBlock/ComplexConditionsOptimized.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/UnreachableBlock/ComplexConditionsOptimized.cs @@ -1,5 +1,6 @@ using System; using System.Reflection.Emit; +using System.Runtime.InteropServices; using System.Runtime.Serialization; using Mono.Linker.Tests.Cases.Expectations.Assertions; using Mono.Linker.Tests.Cases.Expectations.Metadata; @@ -17,6 +18,7 @@ public static void Main () TestSwitch.TestOffset (); TestSwitch2.TestFallThrough (); TestSwitchZero.Test (); + TestSwitch3.TestFallThrough (true); } [Kept] @@ -125,6 +127,54 @@ public static void TestFallThrough () static void Unreached () { } } + [Kept] + class TestSwitch3 + { + [Kept] + [ExpectedInstructionSequence (new[] { + "ldc.i4.4", + "stloc.0", + "ldloc.0", + "pop", + "br.s il_6", + "newobj System.Void System.NotSupportedException::.ctor()", + "throw", + })] + public static object TestFallThrough (bool createReader) + { + object instance; + + switch (ProcessArchitecture, createReader) { + case (Architecture.X86, true): + Unreached (); + break; + case (Architecture.X86, false): + Unreached (); + break; + case (Architecture.X64, true): + Unreached (); + break; + case (Architecture.X64, false): + Unreached (); + break; + case (Architecture.Arm64, true): + Unreached (); + break; + case (Architecture.Arm64, false): + Unreached (); + break; + default: + throw new NotSupportedException (); + } + + return null; + } + + static Architecture ProcessArchitecture => Architecture.Wasm; + + static void Unreached () { } + } + [Kept] class TestSwitchZero {