Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Arzt <arzt.samuel@live.de>2017-08-17 17:57:35 +0300
committerJan Kotas <jkotas@microsoft.com>2017-08-17 17:57:35 +0300
commit55b48213fff4ee0eb131a682a0e7f276ce5afa42 (patch)
tree30576890de1bd81de3ce19caf31daf324e219423 /src/ILVerify
parent232f423b9aa50545635321d4ff6cef71f56c3aaf (diff)
[ILVerify] Implement switch instruction (#4328)
* Added value pop for switch instruction. * Added switch instruction tests and todos for jump target verification. * Added branch target verification with test cases. * Moved switch test cases into seperate file. * Refactored switch/branch tests to use meaningful labels and not use locals.
Diffstat (limited to 'src/ILVerify')
-rw-r--r--src/ILVerify/src/ILImporter.Verify.cs59
-rw-r--r--src/ILVerify/src/Resources/Strings.resx18
-rw-r--r--src/ILVerify/src/VerifierError.cs12
-rw-r--r--src/ILVerify/tests/ILTests/BranchingTests.il78
-rw-r--r--src/ILVerify/tests/ILTests/SwitchTests.il214
5 files changed, 373 insertions, 8 deletions
diff --git a/src/ILVerify/src/ILImporter.Verify.cs b/src/ILVerify/src/ILImporter.Verify.cs
index 2d734b8f5..8d47f5d46 100644
--- a/src/ILVerify/src/ILImporter.Verify.cs
+++ b/src/ILVerify/src/ILImporter.Verify.cs
@@ -360,6 +360,57 @@ namespace Internal.IL
VerificationError(VerifierError.StackUnexpected, src, dst);
}
+ void CheckIsValidBranchTarget(BasicBlock src, BasicBlock target)
+ {
+ if (src.TryIndex != target.TryIndex)
+ {
+ if (src.TryIndex == null)
+ VerificationError(VerifierError.BranchIntoTry);
+ else if (target.TryIndex == null)
+ VerificationError(VerifierError.BranchOutOfTry);
+ else
+ {
+ if (_exceptionRegions[(int)src.TryIndex].ILRegion.TryOffset < _exceptionRegions[(int)target.TryIndex].ILRegion.TryOffset)
+ VerificationError(VerifierError.BranchIntoTry);
+ else
+ VerificationError(VerifierError.BranchOutOfTry);
+ }
+ return;
+ }
+
+ if (src.FilterIndex != target.FilterIndex)
+ {
+ if (src.FilterIndex == null)
+ VerificationError(VerifierError.BranchIntoFilter);
+ else if (target.HandlerIndex == null)
+ VerificationError(VerifierError.BranchOutOfFilter);
+ else
+ {
+ if (_exceptionRegions[(int)src.FilterIndex].ILRegion.FilterOffset < _exceptionRegions[(int)target.FilterIndex].ILRegion.FilterOffset)
+ VerificationError(VerifierError.BranchIntoFilter);
+ else
+ VerificationError(VerifierError.BranchOutOfFilter);
+ }
+ return;
+ }
+
+ if (src.HandlerIndex != target.HandlerIndex)
+ {
+ if (src.HandlerIndex == null)
+ VerificationError(VerifierError.BranchIntoHandler);
+ else if (target.HandlerIndex == null)
+ VerificationError(VerifierError.BranchOutOfHandler);
+ else
+ {
+ if (_exceptionRegions[(int)src.HandlerIndex].ILRegion.HandlerOffset < _exceptionRegions[(int)target.HandlerIndex].ILRegion.HandlerOffset)
+ VerificationError(VerifierError.BranchIntoHandler);
+ else
+ VerificationError(VerifierError.BranchOutOfHandler);
+ }
+ return;
+ }
+ }
+
// For now, match PEVerify type formating to make it easy to compare with baseline
static string TypeToStringForIsAssignable(TypeDesc type)
{
@@ -1036,20 +1087,24 @@ namespace Internal.IL
void ImportSwitchJump(int jmpBase, int[] jmpDelta, BasicBlock fallthrough)
{
+ var value = Pop();
+ CheckIsAssignable(value, StackValue.CreatePrimitive(StackValueKind.Int32));
+
for (int i = 0; i < jmpDelta.Length; i++)
{
BasicBlock target = _basicBlocks[jmpBase + jmpDelta[i]];
+ CheckIsValidBranchTarget(_currentBasicBlock, target);
ImportFallthrough(target);
}
if (fallthrough != null)
ImportFallthrough(fallthrough);
-
- throw new NotImplementedException($"{nameof(ImportSwitchJump)} not implemented");
}
void ImportBranch(ILOpcode opcode, BasicBlock target, BasicBlock fallthrough)
{
+ CheckIsValidBranchTarget(_currentBasicBlock, target);
+
switch (opcode)
{
case ILOpcode.br:
diff --git a/src/ILVerify/src/Resources/Strings.resx b/src/ILVerify/src/Resources/Strings.resx
index c14d1a18f..3d4808683 100644
--- a/src/ILVerify/src/Resources/Strings.resx
+++ b/src/ILVerify/src/Resources/Strings.resx
@@ -120,6 +120,24 @@
<data name="ArrayByRef" xml:space="preserve">
<value>Array of ELEMENT_TYPE_BYREF or ELEMENT_TYPE_TYPEDBYREF.</value>
</data>
+ <data name="BranchIntoFilter" xml:space="preserve">
+ <value>Branch into exception filter block.</value>
+ </data>
+ <data name="BranchIntoHandler" xml:space="preserve">
+ <value>Branch into exception handler block.</value>
+ </data>
+ <data name="BranchIntoTry" xml:space="preserve">
+ <value>Branch into try block.</value>
+ </data>
+ <data name="BranchOutOfFilter" xml:space="preserve">
+ <value>Branch out of exception filter block.</value>
+ </data>
+ <data name="BranchOutOfHandler" xml:space="preserve">
+ <value>Branch out of exception handler block.</value>
+ </data>
+ <data name="BranchOutOfTry" xml:space="preserve">
+ <value>Branch out of try block.</value>
+ </data>
<data name="CallAbstract" xml:space="preserve">
<value>Call not allowed on abstract methods.</value>
</data>
diff --git a/src/ILVerify/src/VerifierError.cs b/src/ILVerify/src/VerifierError.cs
index 014448588..3ead0c61e 100644
--- a/src/ILVerify/src/VerifierError.cs
+++ b/src/ILVerify/src/VerifierError.cs
@@ -63,12 +63,12 @@ namespace ILVerify
Endfinally, //"Endfinally from outside a finally handler."
Endfilter, //"Endfilter from outside an exception filter block."
//E_ENDFILTER_MISSING "Missing Endfilter."
- //E_BR_INTO_TRY "Branch into try block."
- //E_BR_INTO_HND "Branch into exception handler block."
- //E_BR_INTO_FIL "Branch into exception filter block."
- //E_BR_OUTOF_TRY "Branch out of try block."
- //E_BR_OUTOF_HND "Branch out of exception handler block."
- //E_BR_OUTOF_FIL "Branch out of exception filter block."
+ BranchIntoTry, //"Branch into try block."
+ BranchIntoHandler, //"Branch into exception handler block."
+ BranchIntoFilter, //"Branch into exception filter block."
+ BranchOutOfTry, //"Branch out of try block."
+ BranchOutOfHandler, //"Branch out of exception handler block."
+ BranchOutOfFilter, //"Branch out of exception filter block."
//E_BR_OUTOF_FIN "Branch out of finally block."
//E_RET_FROM_TRY "Return out of try block."
//E_RET_FROM_HND "Return out of exception handler block."
diff --git a/src/ILVerify/tests/ILTests/BranchingTests.il b/src/ILVerify/tests/ILTests/BranchingTests.il
index 57554cafe..09b3b35bf 100644
--- a/src/ILVerify/tests/ILTests/BranchingTests.il
+++ b/src/ILVerify/tests/ILTests/BranchingTests.il
@@ -66,4 +66,82 @@
IL_0013: pop
IL_0014: ret
}
+
+ .method static public hidebysig void Branching.InsideTry_Valid() cil managed
+ {
+ .maxstack 2
+
+ .try
+ {
+ ldc.i4.s 10
+ ldc.i4.s 5
+ bne.un.s lbl_true
+
+ nop
+ br.s lbl_leave
+
+ lbl_true: nop
+
+ lbl_leave: leave.s lbl_ret
+ }
+ catch [System.Runtime]System.Object
+ {
+ pop
+ leave.s lbl_ret
+ }
+
+ lbl_ret: ret
+ }
+
+ .method static public hidebysig void Branching.OutOfTry_Invalid_BranchOutOfTry() cil managed
+ {
+ .maxstack 2
+
+ .try
+ {
+ ldc.i4.s 10
+ ldc.i4.s 5
+ bne.un.s lbl_true
+
+ nop
+ br.s lbl_ret
+
+ lbl_true: nop
+
+ lbl_leave: leave.s lbl_ret
+ }
+ catch [System.Runtime]System.Object
+ {
+ pop
+ leave.s lbl_ret
+ }
+
+ lbl_ret: ret
+ }
+
+ .method static public hidebysig void Branching.IntoTry_Invalid_BranchIntoTry() cil managed
+ {
+ .maxstack 2
+
+ ldc.i4.s 10
+ ldc.i4.s 5
+ bne.un.s lbl_true
+
+ nop
+ br.s lbl_ret
+
+ .try
+ {
+ lbl_true: nop
+
+ leave.s lbl_ret
+ }
+ catch [System.Runtime]System.Object
+ {
+ pop
+ leave.s lbl_ret
+ }
+
+ lbl_ret: ret
+ }
}
diff --git a/src/ILVerify/tests/ILTests/SwitchTests.il b/src/ILVerify/tests/ILTests/SwitchTests.il
new file mode 100644
index 000000000..22fc68e3c
--- /dev/null
+++ b/src/ILVerify/tests/ILTests/SwitchTests.il
@@ -0,0 +1,214 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+.assembly extern System.Runtime
+{
+}
+
+.assembly SwitchTests
+{
+}
+
+.class public auto ansi beforefieldinit SwitchTestsType
+ extends [System.Runtime]System.Object
+{
+ .method static public hidebysig void Switch.Int32Value_Valid() cil managed
+ {
+ .maxstack 1
+
+ ldc.i4.s 10
+ switch (lbl_ret, lbl_a, lbl_a, lbl_b, lbl_b)
+
+ br.s lbl_ret
+
+ lbl_a: nop
+ br.s lbl_ret
+
+ lbl_b: nop
+
+ lbl_ret: ret
+ }
+
+ .method static public hidebysig void Switch.Int64Value_Invalid_StackUnexpected() cil managed
+ {
+ .maxstack 1
+
+ ldc.i8 10
+ switch (lbl_ret, lbl_a, lbl_a, lbl_b, lbl_b)
+
+ br.s lbl_ret
+
+ lbl_a: nop
+ br.s lbl_ret
+
+ lbl_b: nop
+
+ lbl_ret: ret
+ }
+
+ .method static public hidebysig void Switch.InsideTry_Valid() cil managed
+ {
+ .maxstack 1
+
+ .try
+ {
+ ldc.i4.s 10
+ switch (lbl_leave, lbl_a, lbl_a, lbl_b, lbl_b)
+
+ br.s lbl_leave
+
+ lbl_a: nop
+ br.s lbl_leave
+
+ lbl_b: nop
+
+ lbl_leave: leave.s lbl_ret
+ }
+ catch [System.Runtime]System.Object
+ {
+ nop
+ leave.s lbl_ret
+ }
+
+ lbl_ret: ret
+ }
+
+ .method static public hidebysig void Switch.IntoTry_Invalid_BranchIntoTry() cil managed
+ {
+ .maxstack 1
+
+ ldc.i4.s 10
+ switch (lbl_ret, lbl_a)
+
+ br.s lbl_ret
+
+ .try
+ {
+ lbl_a: nop
+ br.s lbl_leave
+
+ lbl_leave: leave.s lbl_ret
+ }
+ catch [System.Runtime]System.Object
+ {
+ nop
+ leave.s lbl_ret
+ }
+
+ lbl_ret: ret
+ }
+
+ .method static public hidebysig void Switch.OutOfTry_Invalid_BranchOutOfTry() cil managed
+ {
+ .maxstack 1
+
+ .try
+ {
+ ldc.i4.s 10
+ switch (lbl_ret, lbl_a)
+
+ br.s lbl_leave
+
+ lbl_a: nop
+ br.s lbl_leave
+
+ lbl_leave: leave.s lbl_ret
+ }
+ catch [System.Runtime]System.Object
+ {
+ nop
+ leave.s lbl_ret
+ }
+
+ lbl_ret: ret
+ }
+
+ .method static public hidebysig void Switch.NestedOutOfTry_Invalid_BranchOutOfTry() cil managed
+ {
+ .maxstack 1
+
+ .try
+ {
+ .try
+ {
+ ldc.i4.s 10
+ switch (lbl_leave, lbl_a, lbl_leave2)
+
+ br.s lbl_leave
+
+ lbl_a: nop
+ br.s lbl_leave
+
+ lbl_leave: leave.s lbl_leave2
+ }
+ catch [System.Runtime]System.Object
+ {
+ pop
+ leave.s lbl_leave2
+ }
+
+ lbl_leave2: leave.s lbl_ret
+ }
+ catch [System.Runtime]System.Object
+ {
+ pop
+ leave.s lbl_ret
+ }
+
+ lbl_ret: ret
+ }
+
+ .method static public hidebysig void Switch.NestedIntoTry_Invalid_BranchIntoTry() cil managed
+ {
+ .maxstack 1
+
+ .try
+ {
+ ldc.i4.s 10
+ switch (lbl_leave, lbl_a, lbl_b)
+
+ br.s lbl_leave
+
+ lbl_a: nop
+ br.s lbl_leave
+
+ .try
+ {
+ lbl_b: nop
+ leave.s lbl_leave
+ }
+ catch [System.Runtime]System.Object
+ {
+ pop
+ leave.s lbl_leave
+ }
+
+ lbl_leave: leave.s lbl_ret
+ }
+ catch [System.Runtime]System.Object
+ {
+ pop
+ leave.s lbl_ret
+ }
+
+ lbl_ret: ret
+ }
+
+ .method static public hidebysig void Switch.ObjectValue_Invalid_StackUnexpected() cil managed
+ {
+ .maxstack 1
+
+ ldnull
+ switch (lbl_ret, lbl_a, lbl_a, lbl_b, lbl_b)
+
+ br.s lbl_ret
+
+ lbl_a: nop
+ br.s lbl_ret
+
+ lbl_b: nop
+
+ lbl_ret: ret
+ }
+}