diff options
author | Samuel Arzt <arzt.samuel@live.de> | 2017-11-10 17:13:06 +0300 |
---|---|---|
committer | Jan Kotas <jkotas@microsoft.com> | 2017-11-10 17:13:06 +0300 |
commit | c22aab437100a45a6e721a8e773dc43a6a5b789e (patch) | |
tree | 7ced69250b2c60fe17a5e4205fb9d36fa13b6b30 /src/ILVerify | |
parent | 743e47e1b0a2b851a5a34f18ab3a2d9f975b57e3 (diff) |
[ILVerify] Implement missing cast, box and leave verifications. (#4903)
* Added missing castclass verifications.
* Added tests for new castclass verifications.
* Added missing box verifications.
* Added tests for new box verifications.
* Implemented valid leave target verification.
* Added tests for leave target verification.
* Added Verifier errors for BadBranch, UnknownOpcode and MethodFallthrough.
* Changed disjoint try block determination algorithm and added additional test cases.
Diffstat (limited to 'src/ILVerify')
-rw-r--r-- | src/ILVerify/src/ILImporter.Verify.cs | 234 | ||||
-rw-r--r-- | src/ILVerify/src/Resources/Strings.resx | 36 | ||||
-rw-r--r-- | src/ILVerify/src/VerifierError.cs | 20 | ||||
-rw-r--r-- | src/ILVerify/tests/ILTests/CastingTests.il | 69 | ||||
-rw-r--r-- | src/ILVerify/tests/ILTests/ExceptionRegionTests.il | 711 |
5 files changed, 1014 insertions, 56 deletions
diff --git a/src/ILVerify/src/ILImporter.Verify.cs b/src/ILVerify/src/ILImporter.Verify.cs index 144c767ba..e8819dedd 100644 --- a/src/ILVerify/src/ILImporter.Verify.cs +++ b/src/ILVerify/src/ILImporter.Verify.cs @@ -548,6 +548,118 @@ again: VerificationError(VerifierError.StackUnexpected, src, dst); } + private void CheckIsValidLeaveTarget(BasicBlock src, BasicBlock target) + { + // If the source is within filter, target shall be within the same + if (src.FilterIndex.HasValue && src.FilterIndex != target.FilterIndex) + { + VerificationError(VerifierError.LeaveOutOfFilter); + } + + // If the source is within fault handler or finally handler, target shall be within the same + if (src.HandlerIndex.HasValue && src.HandlerIndex != target.HandlerIndex) + { + var regionKind = _exceptionRegions[src.HandlerIndex.Value].ILRegion.Kind; + if (regionKind == ILExceptionRegionKind.Fault) + VerificationError(VerifierError.LeaveOutOfFault); + else if (regionKind == ILExceptionRegionKind.Finally) + VerificationError(VerifierError.LeaveOutOfFinally); + } + + // If the source is within a try block, target shall be within the same or an enclosing try block + // or the first instruction of a disjoint try block + // or not within any try block + bool invalidLeaveIntoTry = false; + if (src.TryIndex.HasValue && src.TryIndex != target.TryIndex) + { + if (target.TryIndex.HasValue) + { + ref var srcRegion = ref _exceptionRegions[src.TryIndex.Value].ILRegion; + ref var targetRegion = ref _exceptionRegions[target.TryIndex.Value].ILRegion; + + // Target is not enclosing source + if (targetRegion.TryOffset > srcRegion.TryOffset || + src.StartOffset >= targetRegion.TryOffset + targetRegion.TryLength) + { + // Target is not first instruction + if (target.StartOffset != targetRegion.TryOffset) + { + VerificationError(VerifierError.LeaveIntoTry); + invalidLeaveIntoTry = true; + } + else if (srcRegion.TryOffset <= targetRegion.TryOffset && + srcRegion.TryOffset + srcRegion.TryLength > targetRegion.TryOffset) // Source is enclosing target + { + if (!IsDirectChildRegion(src, target)) + { + VerificationError(VerifierError.LeaveIntoTry); + invalidLeaveIntoTry = true; + } + } + else if (!IsDisjointTryBlock(ref targetRegion, ref srcRegion)) + { + VerificationError(VerifierError.LeaveIntoTry); + invalidLeaveIntoTry = true; + } + } + } + } + + // If the source is within a catch or filtered handler, target shall be within same catch or filtered handler + // or within the associated try block + // or within a try block enclosing the catch / filtered handler + // or the first instruction of a disjoint try block + // or not within any try block + if (src.HandlerIndex.HasValue && src.HandlerIndex != target.HandlerIndex) + { + if (target.TryIndex.HasValue) + { + ref var srcRegion = ref _exceptionRegions[target.TryIndex.Value].ILRegion; + ref var targetRegion = ref _exceptionRegions[target.TryIndex.Value].ILRegion; + + // If target is not associated try block, and not enclosing srcRegion + if (target.TryIndex != src.HandlerIndex && + (targetRegion.TryOffset > srcRegion.HandlerOffset || + targetRegion.TryOffset + targetRegion.TryLength < srcRegion.HandlerOffset)) + { + // If target is not first instruction of try, or not a direct sibling + if (target.StartOffset != targetRegion.TryOffset || !IsDisjointTryBlock(ref targetRegion, ref srcRegion)) + VerificationError(VerifierError.LeaveIntoTry); + } + } + } + + // If the target is within a filter or handler, source shall be within same + if (target.HandlerIndex.HasValue && src.HandlerIndex != target.HandlerIndex) + { + ref var targetRegion = ref _exceptionRegions[target.HandlerIndex.Value].ILRegion; + // If target region is not enclosing source + if (targetRegion.HandlerOffset > src.StartOffset || targetRegion.HandlerOffset + targetRegion.HandlerLength < src.StartOffset) + VerificationError(VerifierError.LeaveIntoHandler); + } + if (target.FilterIndex.HasValue && src.FilterIndex != target.FilterIndex) + { + ref var targetRegion = ref _exceptionRegions[target.FilterIndex.Value].ILRegion; + var filterLength = targetRegion.HandlerOffset - targetRegion.FilterOffset; + + // If target region is not enclosing source + if (targetRegion.FilterOffset > src.StartOffset || targetRegion.FilterOffset + filterLength < src.StartOffset) + VerificationError(VerifierError.LeaveIntoFilter); + } + + // If the target is within a try block (except first instruction), source shall be within same + // or within associated handler + if (!invalidLeaveIntoTry && target.TryIndex.HasValue && src.TryIndex != target.TryIndex) + { + ref var targetRegion = ref _exceptionRegions[target.TryIndex.Value].ILRegion; + + if (target.StartOffset != targetRegion.TryOffset && // Not first instruction + (!src.HandlerIndex.HasValue || src.HandlerIndex != target.TryIndex) && // Not associated handler + (targetRegion.TryOffset > src.StartOffset || targetRegion.TryOffset + targetRegion.TryLength < src.StartOffset)) // Target region does not enclose source + VerificationError(VerifierError.LeaveIntoTry); + } + } + bool IsValidBranchTarget(BasicBlock src, BasicBlock target, bool reportErrors = true) { bool isValid = true; @@ -557,7 +669,7 @@ again: if (src.TryIndex == null) { // Branching to first instruction of try-block is valid - if (target.StartOffset != _exceptionRegions[(int)target.TryIndex].ILRegion.TryOffset || !IsDirectChildRegion(src, target)) + if (target.StartOffset != _exceptionRegions[target.TryIndex.Value].ILRegion.TryOffset || !IsDirectChildRegion(src, target)) { if (reportErrors) VerificationError(VerifierError.BranchIntoTry); @@ -572,8 +684,8 @@ again: } else { - ref var srcRegion = ref _exceptionRegions[(int)src.TryIndex].ILRegion; - ref var targetRegion = ref _exceptionRegions[(int)target.TryIndex].ILRegion; + ref var srcRegion = ref _exceptionRegions[src.TryIndex.Value].ILRegion; + ref var targetRegion = ref _exceptionRegions[target.TryIndex.Value].ILRegion; // If target is inside source region if (srcRegion.TryOffset <= targetRegion.TryOffset && target.StartOffset < srcRegion.TryOffset + srcRegion.TryLength) @@ -611,8 +723,8 @@ again: } else { - ref var srcRegion = ref _exceptionRegions[(int)src.FilterIndex].ILRegion; - ref var targetRegion = ref _exceptionRegions[(int)target.FilterIndex].ILRegion; + ref var srcRegion = ref _exceptionRegions[src.FilterIndex.Value].ILRegion; + ref var targetRegion = ref _exceptionRegions[target.FilterIndex.Value].ILRegion; if (srcRegion.FilterOffset <= targetRegion.FilterOffset) { if (reportErrors) @@ -644,8 +756,8 @@ again: } else { - ref var srcRegion = ref _exceptionRegions[(int)src.HandlerIndex].ILRegion; - ref var targetRegion = ref _exceptionRegions[(int)target.HandlerIndex].ILRegion; + ref var srcRegion = ref _exceptionRegions[src.HandlerIndex.Value].ILRegion; + ref var targetRegion = ref _exceptionRegions[target.HandlerIndex.Value].ILRegion; if (srcRegion.HandlerOffset <= targetRegion.HandlerOffset) { if (reportErrors) @@ -673,7 +785,7 @@ again: /// <returns>True if <paramref name="enclosedBlock"/> is a direct child try region of <paramref name="enclosingBlock"/>.</returns> bool IsDirectChildRegion(BasicBlock enclosingBlock, BasicBlock enclosedBlock) { - var enclosedRegion = _exceptionRegions[(int)enclosedBlock.TryIndex].ILRegion; + ref var enclosedRegion = ref _exceptionRegions[enclosedBlock.TryIndex.Value].ILRegion; // Walk from enclosed try start backwards and check each BasicBlock whether it is a try-start for (int i = enclosedRegion.TryOffset - 1; i > enclosingBlock.StartOffset; --i) @@ -684,7 +796,7 @@ again: if (block.TryStart && block.TryIndex != enclosingBlock.TryIndex) { - var blockRegion = _exceptionRegions[(int)block.TryIndex].ILRegion; + ref var blockRegion = ref _exceptionRegions[block.TryIndex.Value].ILRegion; // blockRegion is actually enclosing enclosedRegion if (blockRegion.TryOffset + blockRegion.TryLength > enclosedRegion.TryOffset) return false; @@ -694,6 +806,57 @@ again: return true; } + /// <summary> + /// Checks whether the try block <paramref name="disjoint"/> is a disjoint try block relative to <paramref name="source"/>. + /// </summary> + /// <returns>True if <paramref name="disjoint"/> is a disjoint try block relative to <paramref name="source"/>.</returns> + bool IsDisjointTryBlock(ref ILExceptionRegion disjoint, ref ILExceptionRegion source) + { + if (source.TryOffset <= disjoint.TryOffset && source.TryOffset + source.TryLength >= disjoint.TryOffset + disjoint.TryLength) + { + // source is enclosing disjoint + return false; + } + + // Walk from disjoint region backwards and check for enclosing exception regions. + for (int i = disjoint.TryOffset - 1; i >= 0; --i) + { + var block = _basicBlocks[i]; + if (block == null) + continue; + + if (block.TryStart) + { + ref var blockRegion = ref _exceptionRegions[block.TryIndex.Value].ILRegion; + // blockRegion is enclosing disjoint, but not source + if (blockRegion.TryOffset + blockRegion.TryLength > disjoint.TryOffset && + (blockRegion.TryOffset > source.TryOffset || blockRegion.TryOffset + blockRegion.TryLength <= source.TryOffset)) + return false; + } + + if (block.HandlerStart) + { + ref var blockRegion = ref _exceptionRegions[block.HandlerIndex.Value].ILRegion; + // blockRegion is enclosing secondRegion, but not source + if (blockRegion.HandlerOffset + blockRegion.HandlerLength > disjoint.TryOffset && + (blockRegion.HandlerOffset > source.TryOffset || blockRegion.HandlerOffset + blockRegion.HandlerLength <= source.TryOffset)) + return false; + } + + if (block.FilterStart) + { + ref var blockRegion = ref _exceptionRegions[block.FilterIndex.Value].ILRegion; + // blockRegion is enclosing secondRegion, but not source + var filterLength = blockRegion.HandlerOffset - blockRegion.FilterOffset; + if (blockRegion.FilterOffset + filterLength > disjoint.TryOffset && + (blockRegion.FilterOffset > source.TryOffset || blockRegion.FilterOffset + filterLength <= source.TryOffset)) + return false; + } + } + + return true; + } + // For now, match PEVerify type formating to make it easy to compare with baseline static string TypeToStringForIsAssignable(TypeDesc type) { @@ -1125,11 +1288,9 @@ again: var value = Pop(); - // TODO - // VerifyIsObjRef(tiVal); + CheckIsObjRef(value); - // TODO - // verCheckClassAccess(pResolvedToken); + Check(_method.OwningType.CanAccess(type), VerifierError.TypeAccess); Push(StackValue.CreateObjRef(type)); } @@ -1885,19 +2046,14 @@ again: var targetType = StackValue.CreateFromType(type); - // TODO: Change the error message to say "cannot box byref" instead - Check(!IsByRefLike(targetType), VerifierError.ExpectedValClassObjRefVariable, targetType); + Check(!IsByRefLike(targetType), VerifierError.BoxByRef, targetType); -#if false - VerifyIsBoxable(tiBox); + Check(type.IsPrimitive || targetType.Kind == StackValueKind.ObjRef || + type.IsGenericParameter || type.IsValueType, VerifierError.ExpectedValClassObjRefVariable); - VerifyAndReportFound(m_jitInfo->satisfiesClassConstraints(clsHnd), - tiBox, - MVER_E_UNSATISFIED_BOX_OPERAND); //"boxed type has unsatisfied class constraints"); + Check(type.CheckConstraints(), VerifierError.UnsatisfiedBoxOperand); - //Check for access to the type. - verCheckClassAccess(pResolvedToken); -#endif + Check(_method.OwningType.CanAccess(type), VerifierError.TypeAccess); CheckIsAssignable(value, targetType); @@ -1920,7 +2076,7 @@ again: PropagateThisState(_currentBasicBlock, target); MarkBasicBlock(target); - // TODO + CheckIsValidLeaveTarget(_currentBasicBlock, target); } void ImportEndFinally() @@ -2285,6 +2441,21 @@ again: _pendingPrefix &= ~prefix; } + void ReportInvalidBranchTarget(int targetOffset) + { + VerificationError(VerifierError.BadBranch); + } + + void ReportFallthroughAtEndOfMethod() + { + VerificationError(VerifierError.MethodFallthrough); + } + + void ReportInvalidInstruction(ILOpcode opcode) + { + VerificationError(VerifierError.UnknownOpcode); + } + // // Deprecated // @@ -2308,20 +2479,5 @@ again: { throw new PlatformNotSupportedException("TypedReference not supported in .NET Core"); } - - private void ReportInvalidBranchTarget(int targetOffset) - { - throw new NotImplementedException(); - } - - private void ReportFallthroughAtEndOfMethod() - { - throw new NotImplementedException(); - } - - private void ReportInvalidInstruction(ILOpcode opcode) - { - throw new NotImplementedException(); - } } } diff --git a/src/ILVerify/src/Resources/Strings.resx b/src/ILVerify/src/Resources/Strings.resx index 543e9b44f..9e7b84f19 100644 --- a/src/ILVerify/src/Resources/Strings.resx +++ b/src/ILVerify/src/Resources/Strings.resx @@ -120,6 +120,12 @@ <data name="ArrayByRef" xml:space="preserve"> <value>Array of ELEMENT_TYPE_BYREF or ELEMENT_TYPE_TYPEDBYREF.</value> </data> + <data name="BadBranch" xml:space="preserve"> + <value>Branch out of the method.</value> + </data> + <data name="BoxByRef" xml:space="preserve"> + <value>Cannot box byref.</value> + </data> <data name="BranchIntoFilter" xml:space="preserve"> <value>Branch into exception filter block.</value> </data> @@ -222,9 +228,30 @@ <data name="LdvirtftnOnStatic" xml:space="preserve"> <value>ldvirtftn on static.</value> </data> + <data name="LeaveIntoFilter" xml:space="preserve"> + <value>Leave into filter block.</value> + </data> + <data name="LeaveIntoHandler" xml:space="preserve"> + <value>Leave into exception handler block.</value> + </data> + <data name="LeaveIntoTry" xml:space="preserve"> + <value>Leave into try block.</value> + </data> + <data name="LeaveOutOfFault" xml:space="preserve"> + <value>Leave out of fault block.</value> + </data> + <data name="LeaveOutOfFilter" xml:space="preserve"> + <value>Leave out of filter block.</value> + </data> + <data name="LeaveOutOfFinally" xml:space="preserve"> + <value>Leave out of finally block.</value> + </data> <data name="MethodAccess" xml:space="preserve"> <value>Method is not visible.</value> </data> + <data name="MethodFallthrough" xml:space="preserve"> + <value>Fall through end of the method without returning.</value> + </data> <data name="PathStackDepth" xml:space="preserve"> <value>Stack depth differs depending on path.</value> </data> @@ -312,12 +339,18 @@ <data name="TryNonEmptyStack" xml:space="preserve"> <value>Attempt to enter a try block with nonempty stack.</value> </data> + <data name="TypeAccess" xml:space="preserve"> + <value>Type is not visible.</value> + </data> <data name="Unaligned" xml:space="preserve"> <value>Missing ldind, stind, ldfld, stfld, ldobj, stobj, initblk, cpblk.</value> </data> <data name="UninitStack" xml:space="preserve"> <value>Uninitialized item on stack.</value> </data> + <data name="UnknownOpcode" xml:space="preserve"> + <value>Unknown opcode.</value> + </data> <data name="UnmanagedPointer" xml:space="preserve"> <value>Unmanaged pointers are not a verifiable type.</value> </data> @@ -327,6 +360,9 @@ <data name="UnrecognizedLocalNumber" xml:space="preserve"> <value>Unrecognized local variable number.</value> </data> + <data name="UnsatisfiedBoxOperand" xml:space="preserve"> + <value>Type operand of box instruction has unsatisfied class type parameter constraints.</value> + </data> <data name="UnsatisfiedMethodInst" xml:space="preserve"> <value>Method instantiation has unsatisfied method type parameter constraints.</value> </data> diff --git a/src/ILVerify/src/VerifierError.cs b/src/ILVerify/src/VerifierError.cs index df2f02329..51e4ad689 100644 --- a/src/ILVerify/src/VerifierError.cs +++ b/src/ILVerify/src/VerifierError.cs @@ -25,9 +25,9 @@ namespace ILVerify //E_FOUND "[found %s]" //E_EXPECTED "[expected %s]" - //E_UNKNOWN_OPCODE "Unknown opcode [0x%08X]." - //E_SIG_CALLCONV "Unknown calling convention [0x%08X]." - //E_SIG_ELEMTYPE "Unknown ELEMENT_TYPE [0x%08x]." + UnknownOpcode, // Unknown opcode. + //E_SIG_CALLCONV "Unknown calling convention [0x%08X]." + //E_SIG_ELEMTYPE "Unknown ELEMENT_TYPE [0x%08x]." //E_RET_SIG "[return sig]" //E_FIELD_SIG "[field sig]" @@ -36,7 +36,7 @@ namespace ILVerify //E_STACK_TOO_LARGE "Stack is too large." //E_ARRAY_NAME_LONG "Array name is too long." - //E_FALLTHRU "fall through end of the method without returning." + 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." @@ -59,6 +59,12 @@ namespace ILVerify //E_FALLTHRU_INTO_HND "fallthru into an exception handler." //E_FALLTHRU_INTO_FIL "fallthru into an exception filter." //E_LEAVE "Leave from outside a try or catch block." + LeaveIntoTry, // Leave into try block. + LeaveIntoHandler, // Leave into exception handler block. + LeaveIntoFilter, // Leave into filter block. + LeaveOutOfFilter, // Leave out of filter block. + LeaveOutOfFinally, // Leave out of finally block. + LeaveOutOfFault, // Leave out of fault block. Rethrow, // Rethrow from outside a catch handler. Endfinally, // Endfinally from outside a finally handler. Endfilter, // Endfilter from outside an exception filter block. @@ -131,6 +137,7 @@ namespace ILVerify //E_ARGLIST "Allowed only in vararg methods." ValueTypeExpected, // Value type expected. //E_OPEN_DLGT_PROT_ACC "Protected method access through an open instance delegate is not verifiable." + TypeAccess, // Type is not visible. MethodAccess, // Method is not visible. FieldAccess, // Field is not visible. //E_DEAD "Item is unusable at this point." @@ -166,7 +173,7 @@ namespace ILVerify //E_TAIL_RET_TYPE "Tail call return type not compatible." TailStackEmpty, // Stack not empty after tail call. //E_METHOD_END "Method ends in the middle of an instruction." - //E_BAD_BRANCH "Branch out of the method." + BadBranch, // Branch out of the method. //E_FIN_OVERLAP "Finally handler blocks overlap." //E_LEXICAL_NESTING "Lexical nesting." Volatile, // Missing ldsfld, stsfld, ldind, stind, ldfld, stfld, ldobj, stobj, initblk, or cpblk. @@ -184,6 +191,7 @@ namespace ILVerify //E_SIG_C_VC "ELEMENT_TYPE_CLASS ValueClass in signature." //E_SIG_VC_C "ELEMENT_TYPE_VALUETYPE non-ValueClass in signature." //E_BOX_PTR_TO_STACK "Box operation on TypedReference, ArgHandle, or ArgIterator." + BoxByRef, // Cannot box byref. //E_SIG_BYREF_TB_AH "ByRef of TypedReference, ArgHandle, or ArgIterator." //E_SIG_ARRAY_TB_AH "Array of TypedReference, ArgHandle, or ArgIterator." EndfilterStack, // Stack not empty when leaving an exception filter. @@ -221,7 +229,7 @@ namespace ILVerify UnsatisfiedMethodInst, // Method instantiation has unsatisfied method type parameter constraints. UnsatisfiedMethodParentInst, // Method parent instantiation has unsatisfied class type parameter constraints. //E_UNSATISFIED_FIELD_PARENT_INST "Field parent instantiation has unsatisfied class type parameter constraints." - //E_UNSATISFIED_BOX_OPERAND "Type operand of box instruction has unsatisfied class type parameter constraints." + UnsatisfiedBoxOperand, // Type operand of box instruction has unsatisfied class type parameter constraints. ConstrainedCallWithNonByRefThis, // The 'this' argument to a constrained call must have ByRef type. //E_CONSTRAINED_OF_NON_VARIABLE_TYPE "The operand to a constrained prefix instruction must be a type parameter." //E_READONLY_UNEXPECTED_CALLEE "The readonly prefix may only be applied to calls to array methods returning ByRefs." diff --git a/src/ILVerify/tests/ILTests/CastingTests.il b/src/ILVerify/tests/ILTests/CastingTests.il index 4be6b764e..c4e085927 100644 --- a/src/ILVerify/tests/ILTests/CastingTests.il +++ b/src/ILVerify/tests/ILTests/CastingTests.il @@ -284,6 +284,27 @@ } } +// Class with private nested class +.class public auto ansi beforefieldinit ContainingClass + extends [System.Runtime]System.Object +{ + .class nested private auto ansi beforefieldinit PrivateNestedClass + extends [System.Runtime]System.Object + { + } +} + + +// Test enum +.class public auto ansi sealed Enum + extends [System.Runtime]System.Enum +{ + .field public static literal valuetype Enum EnumValue1 = int32(0) + .field public static literal valuetype Enum EnumValue2 = int32(1) + + .field public specialname rtspecialname int32 value__ +} + .class public auto ansi beforefieldinit CastingTestsType extends [System.Runtime]System.Object { @@ -298,4 +319,52 @@ stloc.0 ret } + + .method public static void Casting.CastToInaccessibleType_Invalid_TypeAccess() cil managed + { + ldnull + castclass ContainingClass/PrivateNestedClass + pop + ret + } + + .method public static void Casting.CastClassInt_Invalid_StackObjRef() cil managed + { + ldc.i4.0 + castclass CastingTestsType + pop + ret + } + + .method public static void Casting.BoxInaccesibleType_Invalid_TypeAccess(class ContainingClass/PrivateNestedClass c) cil managed + { + ldarg.0 + box ContainingClass/PrivateNestedClass + pop + ret + } + + .method public static void Casting.BoxByRefInt_Invalid_BoxByRef.ExpectedValClassObjRefVariable(int32& i) cil managed + { + ldarg.0 + box int32& + pop + ret + } + + .method public static void Casting.BoxToUnsatisfiedConstraint_Invalid_UnsatisfiedBoxOperand(class GenericTypeWithConstrained<class [System.Runtime]System.Object> c) cil managed + { + ldarg.0 + box class GenericTypeWithConstrained<class [System.Runtime]System.Object> + pop + ret + } + + .method public static void Casting.BoxEnum_Valid(valuetype Enum e) cil managed + { + ldarg.0 + box Enum + pop + ret + } } diff --git a/src/ILVerify/tests/ILTests/ExceptionRegionTests.il b/src/ILVerify/tests/ILTests/ExceptionRegionTests.il index 840643c39..8b388044d 100644 --- a/src/ILVerify/tests/ILTests/ExceptionRegionTests.il +++ b/src/ILVerify/tests/ILTests/ExceptionRegionTests.il @@ -15,27 +15,716 @@ { .method public instance void ExceptionRegion.NestedTryFinally_Valid() cil managed { - .try - { + .try + { nop - leave EndTryCatch - } + leave EndTryCatch + } finally { - .try - { + .try + { nop - leave EndFinally - } + leave EndFinally + } catch [System.Runtime]System.Exception { nop - leave EndFinally + leave EndFinally } -EndFinally: + EndFinally: endfinally } -EndTryCatch: + EndTryCatch: + ret + } + + .method public instance void Leave.ToSameFilter_Valid() cil managed + { + .try + { + leave MethodEnd + } + filter + { + pop + leave SameFilter + + SameFilter: + ldc.i4.0 + endfilter + } + { + pop + leave MethodEnd + } + MethodEnd: + ret + } + + .method public instance void Leave.ToOtherFilter_Invalid_LeaveOutOfFilter.LeaveIntoFilter() cil managed + { + .try + { + leave AfterTry + } + filter + { + pop + leave OtherFilter + + ldc.i4.0 + endfilter + } + { + pop + leave MethodEnd + } + AfterTry: + nop + + .try + { + leave MethodEnd + } + filter + { + pop + + OtherFilter: + ldc.i4.0 + endfilter + } + { + pop + leave MethodEnd + } + MethodEnd: + ret + } + + .method public instance void Leave.OutOfFilter_Invalid_LeaveOutOfFilter() cil managed + { + .try + { + leave MethodEnd + } + filter + { + pop + leave MethodEnd + + ldc.i4.0 + endfilter + } + { + pop + leave MethodEnd + } + MethodEnd: + ret + } + + .method public instance void Leave.ToSameFault_Valid() cil managed + { + .try + { + leave MethodEnd + } + fault + { + leave SameFault + + SameFault: + endfault + } + MethodEnd: + ret + } + + .method public instance void Leave.ToSameFinally_Valid() cil managed + { + .try + { + leave MethodEnd + } + finally + { + leave SameFinally + + SameFinally: + endfinally + } + MethodEnd: + ret + } + + .method public instance void Leave.ToOtherFinally_Invalid_LeaveOutOfFinally.LeaveIntoHandler() cil managed + { + .try + { + leave AfterTry + } + finally + { + leave OtherFinally + endfinally + } + AfterTry: + nop + + .try + { + leave MethodEnd + } + finally + { + OtherFinally: + endfinally + } + MethodEnd: + ret + } + + .method public instance void Leave.ToOtherFault_Invalid_LeaveOutOfFault.LeaveIntoFault.LeaveIntoHandler() cil managed + { + .try + { + leave AfterTry + } + fault + { + leave OtherFault + endfault + } + AfterTry: + nop + + .try + { + leave MethodEnd + } + fault + { + OtherFault: + endfault + } + MethodEnd: + ret + } + + .method public instance void Leave.OutOfFinally_Invalid_LeaveOutOfFinally() cil managed + { + .try + { + leave MethodEnd + } + finally + { + leave MethodEnd + endfinally + } + MethodEnd: + ret + } + + .method public instance void Leave.OutOfFault_Invalid_LeaveOutOfFault() cil managed + { + .try + { + leave MethodEnd + } + fault + { + leave MethodEnd + endfault + } + MethodEnd: + ret + } + + .method public instance void Leave.ToSameTry_Valid() cil managed + { + .try + { + leave SameTry + + SameTry: + leave MethodEnd + } + finally + { + endfinally + } + MethodEnd: + ret + } + + .method public instance void Leave.ToEnclosingTry_Valid() cil managed + { + .try + { + .try + { + leave EnclosingTry + } + finally + { + endfinally + } + EnclosingTry: + leave MethodEnd + } + finally + { + endfinally + } + MethodEnd: + ret + } + + .method public instance void Leave.ToFirstInstrOfDisjointTry_Valid() cil managed + { + .try + { + leave DisjointTry + } + finally + { + endfinally + } + + .try + { + DisjointTry: + leave MethodEnd + } + finally + { + endfinally + } + MethodEnd: + ret + } + + .method public instance void Leave.ToFirstInstrOfNestedDisjointTry_Valid() cil managed + { + .try + { + leave DisjointTry + } + finally + { + endfinally + } + + .try + { + .try + { + DisjointTry: + leave MethodEnd + } + finally + { + endfinally + } + } + finally + { + endfinally + } + MethodEnd: + ret + } + + .method public instance void Leave.IntoOtherTry_Invalid_LeaveIntoTry() cil managed + { + .try + { + leave OtherTry + } + finally + { + endfinally + } + + .try + { + nop + OtherTry: + leave MethodEnd + } + finally + { + endfinally + } + MethodEnd: + ret + } + + .method public instance void Leave.ToSecondInstrOfNestedDisjointTry_Invalid_LeaveIntoTry() cil managed + { + .try + { + leave DisjointTry + } + finally + { + endfinally + } + + .try + { + nop + .try + { + DisjointTry: + leave MethodEnd + } + finally + { + endfinally + } + } + finally + { + endfinally + } + MethodEnd: + ret + } + + .method public instance void Leave.ToFirstInstrOfEnclosedTry_Valid() cil managed + { + .try + { + leave EnclosedTry + + .try + { + EnclosedTry: + leave TryEnd + } + finally + { + endfinally + } + TryEnd: + leave MethodEnd + } + finally + { + endfinally + } + MethodEnd: + ret + } + + .method public instance void Leave.FromCatchIntoAssociatedTry_Valid() cil managed + { + .try + { + TryStart: + leave MethodEnd + } + catch [System.Runtime]System.Object + { + leave TryStart + } + MethodEnd: + ret + } + + .method public instance void Leave.ToSameCatch_Valid() cil managed + { + .try + { + leave MethodEnd + } + catch [System.Runtime]System.Object + { + leave SameCatch + + SameCatch: + leave MethodEnd + } + MethodEnd: + ret + } + + .method public instance void Leave.IntoEnclosingTry_Valid() cil managed + { + .try + { + .try + { + leave EnclosingTry + } + catch [System.Runtime]System.Object + { + leave EnclosingTry + } + EnclosingTry: + leave MethodEnd + } + finally + { + endfinally + } + + MethodEnd: + ret + } + + .method public instance void Leave.OutOfCatch_Valid() cil managed + { + .try + { + leave MethodEnd + } + catch [System.Runtime]System.Object + { + leave MethodEnd + } + MethodEnd: + ret + } + + .method public instance void Leave.CatchToFirstInstrOfDisjointTry_Valid() cil managed + { + .try + { + leave AfterTry + } + catch [System.Runtime]System.Object + { + leave DisjointTry + } + AfterTry: + nop + + .try + { + DisjointTry: + leave MethodEnd + } + finally + { + endfinally + } + MethodEnd: + ret + } + + .method public instance void Leave.CatchToFirstInstrOfNestedTry_Valid() cil managed + { + .try + { + leave MethodEnd + } + catch [System.Runtime]System.Object + { + leave NestedTry + + .try + { + NestedTry: + leave MethodEnd + } + finally + { + endfinally + } + + leave MethodEnd + } + + MethodEnd: + ret + } + + .method public instance void Leave.CatchToSecondInstrOfNestedTry_Invalid_LeaveIntoTry() cil managed + { + .try + { + leave MethodEnd + } + catch [System.Runtime]System.Object + { + leave NestedTry + + .try + { + nop + NestedTry: + leave MethodEnd + } + finally + { + endfinally + } + + leave MethodEnd + } + + MethodEnd: + ret + } + + .method public instance void Leave.CatchToEnclosingTry_Valid() cil managed + { + .try + { + leave MethodEnd + } + catch [System.Runtime]System.Object + { + .try + { + leave EnclosingTry + } + finally + { + endfinally + } + + EnclosingTry: + leave MethodEnd + } + + MethodEnd: + ret + } + + .method public instance void Leave.FromOutsideIntoFilter_Invalid_LeaveIntoFilter() cil managed + { + leave IntoFilter + + .try + { + leave MethodEnd + } + filter + { + pop + IntoFilter: + ldc.i4.0 + endfilter + } + { + leave MethodEnd + } + + MethodEnd: + ret + } + + .method public instance void Leave.FromOutsideIntoHandler_Invalid_LeaveIntoHandler() cil managed + { + leave IntoHandler + + .try + { + leave MethodEnd + } + catch [System.Runtime]System.Object + { + pop + IntoHandler: + leave MethodEnd + } + + MethodEnd: + ret + } + + .method public instance void Leave.FromOutsideIntoTry_Invalid_LeaveIntoTry() cil managed + { + leave IntoTry + + .try + { + nop + IntoTry: + leave MethodEnd + } + finally + { + endfinally + } + + MethodEnd: + ret + } + + .method public instance void Leave.FromNestedTryToDisjointTry_Valid() cil managed + { + .try + { + .try + { + leave DisjointTry + } + finally + { + endfinally + } + leave AfterTry + } + finally + { + endfinally + } + AfterTry: + nop + + .try + { + DisjointTry: + leave MethodEnd + } + finally + { + endfinally + } + + MethodEnd: + ret + } + + .method public instance void Leave.FromNestedTryToDisjointTryBackward_Valid() cil managed + { + .try + { + DisjointTry: + leave AfterTry + } + finally + { + endfinally + } + AfterTry: + nop + + .try + { + .try + { + leave DisjointTry + } + finally + { + endfinally + } + leave MethodEnd + } + finally + { + endfinally + } + + MethodEnd: ret } } |