diff options
author | Samuel Arzt <arzt.samuel@live.de> | 2017-11-11 18:10:56 +0300 |
---|---|---|
committer | Jan Kotas <jkotas@microsoft.com> | 2017-11-11 18:10:56 +0300 |
commit | 066cfc2708ec4bca52938d6a5267194fe4b90448 (patch) | |
tree | ec332b793491f0a43588bfba703db00b343d90f6 /src/ILVerify | |
parent | d605bd5547660d07ff1b0e98ddf9649755c7571a (diff) |
[ILVerify] Implement verification of initonly fields (#4914)
* Implemented verification of initonly fields.
* Added tests for initonly field verifications.
Diffstat (limited to 'src/ILVerify')
-rw-r--r-- | src/ILVerify/src/ILImporter.Verify.cs | 15 | ||||
-rw-r--r-- | src/ILVerify/src/Resources/Strings.resx | 3 | ||||
-rw-r--r-- | src/ILVerify/src/VerifierError.cs | 2 | ||||
-rw-r--r-- | src/ILVerify/tests/ILTests/FieldTests.il | 140 |
4 files changed, 156 insertions, 4 deletions
diff --git a/src/ILVerify/src/ILImporter.Verify.cs b/src/ILVerify/src/ILImporter.Verify.cs index e8819dedd..f1eedf754 100644 --- a/src/ILVerify/src/ILImporter.Verify.cs +++ b/src/ILVerify/src/ILImporter.Verify.cs @@ -1847,7 +1847,6 @@ again: var field = ResolveFieldToken(token); TypeDesc instance; - if (isStatic) { Check(field.IsStatic, VerifierError.ExpectedStaticField); @@ -1884,13 +1883,15 @@ again: bool isPermanentHome = false; TypeDesc instance; - if (isStatic) { Check(field.IsStatic, VerifierError.ExpectedStaticField); isPermanentHome = true; instance = null; + + if (field.IsInitOnly) + Check(_method.IsStaticConstructor && field.OwningType == _method.OwningType, VerifierError.Initonly); } else { @@ -1910,6 +1911,9 @@ again: isPermanentHome = actualThis.Kind == StackValueKind.ObjRef || actualThis.IsPermanentHome; instance = actualThis.Type; + + if (field.IsInitOnly) + Check(_method.IsConstructor && field.OwningType == _method.OwningType && actualThis.IsThisPtr, VerifierError.Initonly); } Check(_method.OwningType.CanAccess(field, instance), VerifierError.FieldAccess); @@ -1927,12 +1931,14 @@ again: var field = ResolveFieldToken(token); TypeDesc instance; - if (isStatic) { Check(field.IsStatic, VerifierError.ExpectedStaticField); instance = null; + + if (field.IsInitOnly) + Check(_method.IsStaticConstructor && field.OwningType == _method.OwningType, VerifierError.Initonly); } else { @@ -1951,6 +1957,9 @@ again: CheckIsAssignable(actualThis, declaredThis); instance = actualThis.Type; + + if (field.IsInitOnly) + Check(_method.IsConstructor && field.OwningType == _method.OwningType && actualThis.IsThisPtr, VerifierError.Initonly); } Check(_method.OwningType.CanAccess(field, instance), VerifierError.FieldAccess); diff --git a/src/ILVerify/src/Resources/Strings.resx b/src/ILVerify/src/Resources/Strings.resx index 9e7b84f19..746fea21d 100644 --- a/src/ILVerify/src/Resources/Strings.resx +++ b/src/ILVerify/src/Resources/Strings.resx @@ -219,6 +219,9 @@ <data name="InitLocals" xml:space="preserve"> <value>initlocals must be set for verifiable methods with one or more local variables.</value> </data> + <data name="Initonly" xml:space="preserve"> + <value>Cannot change initonly field outside its .ctor.</value> + </data> <data name="LdftnConstructor" xml:space="preserve"> <value>ldftn/ldvirtftn not allowed on .ctor.</value> </data> diff --git a/src/ILVerify/src/VerifierError.cs b/src/ILVerify/src/VerifierError.cs index 51e4ad689..d1efe85dd 100644 --- a/src/ILVerify/src/VerifierError.cs +++ b/src/ILVerify/src/VerifierError.cs @@ -146,7 +146,7 @@ namespace ILVerify //E_ADDR "Address of not allowed for this item." //E_ADDR_BYREF "Address of not allowed for ByRef." //E_ADDR_LITERAL "Address of not allowed for literal field." - //E_INITONLY "Cannot change initonly field outside its .ctor." + Initonly, // Cannot change initonly field outside its .ctor. //E_WRITE_RVA_STATIC "Cannot modify an imaged based (RVA) static" //E_THROW "Cannot throw this object." CallVirtOnValueType, // Callvirt on a value type method. diff --git a/src/ILVerify/tests/ILTests/FieldTests.il b/src/ILVerify/tests/ILTests/FieldTests.il new file mode 100644 index 000000000..8780250ae --- /dev/null +++ b/src/ILVerify/tests/ILTests/FieldTests.il @@ -0,0 +1,140 @@ +// 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 FieldTests +{ +} + +.class public auto ansi beforefieldinit FieldTestsType + extends [System.Runtime]System.Object +{ + .field public initonly int32 InstanceInitonlyField + .field public static initonly int32 StaticInitonlyField + + .method public instance void Stfld.InitonlyFieldOutsideCtor_Invalid_Initonly() cil managed + { + ldarg.0 + ldc.i4.0 + stfld int32 FieldTestsType::InstanceInitonlyField + ret + } + + .method public instance void Ldflda.InitonlyFieldOutsideCtor_Invalid_Initonly() cil managed + { + ldarg.0 + ldflda int32 FieldTestsType::InstanceInitonlyField + pop + ret + } + + .method public hidebysig instance void 'special.StoreInitonlyField..ctor_Valid'() cil managed { ret } + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + ldarg.0 + call instance void [System.Runtime]System.Object::.ctor() + ldarg.0 + ldc.i4.0 + stfld int32 FieldTestsType::InstanceInitonlyField + ret + } + + .method public hidebysig instance void 'special.LoadAddrInitonlyField..ctor_Valid'(int32) cil managed { ret } + .method public hidebysig specialname rtspecialname instance void .ctor(int32) cil managed + { + ldarg.0 + call instance void [System.Runtime]System.Object::.ctor() + ldarg.0 + ldflda int32 FieldTestsType::InstanceInitonlyField + pop + ret + } + + .method public hidebysig instance void 'special.LoadAddrInitonlyField..ctor_Valid'(int64) cil managed { ret } + .method public hidebysig specialname rtspecialname instance void .ctor(int64) cil managed + { + ldarg.0 + call instance void [System.Runtime]System.Object::.ctor() + ldarg.0 + ldflda int32 FieldTestsType::InstanceInitonlyField + pop + ret + } + + .method public hidebysig instance void 'special.StoreInitonlyFieldOtherType..ctor_Invalid_Initonly'(class OtherType c) cil managed { ret } + .method public hidebysig specialname rtspecialname instance void .ctor(class OtherType c) cil managed + { + ldarg.0 + call instance void [System.Runtime]System.Object::.ctor() + ldarg.1 + ldc.i4.0 + stfld int32 OtherType::InstanceInitonlyField + ret + } + + .method public hidebysig instance void 'special.StoreInitonlyFieldOtherInstance..ctor_Invalid_Initonly'(class FieldTestsType c) cil managed { ret } + .method public hidebysig specialname rtspecialname instance void .ctor(class FieldTestsType c) cil managed + { + ldarg.0 + call instance void [System.Runtime]System.Object::.ctor() + ldarg.1 + ldc.i4.0 + stfld int32 FieldTestsType::InstanceInitonlyField + ret + } + + .method public hidebysig instance void 'special.StsfldInitonlyInCtor..ctor_Invalid_Initonly'(bool) cil managed { ret } + .method public hidebysig specialname rtspecialname instance void .ctor(bool) cil managed + { + ldarg.0 + call instance void [System.Runtime]System.Object::.ctor() + ldc.i4.0 + stsfld int32 FieldTestsType::StaticInitonlyField + ret + } + + .method public hidebysig instance void 'special.LdsfldInitonlyInCtor..ctor_Invalid_Initonly'(char) cil managed { ret } + .method public hidebysig specialname rtspecialname instance void .ctor(char) cil managed + { + ldarg.0 + call instance void [System.Runtime]System.Object::.ctor() + ldsflda int32 FieldTestsType::StaticInitonlyField + pop + ret + } + + .method public hidebysig instance void 'special.LdsfldStslfdInitonlyCctor..cctor_Valid'() cil managed { ret } + .method public hidebysig specialname rtspecialname instance void .cctor() cil managed + { + ldsflda int32 FieldTestsType::StaticInitonlyField + pop + ldc.i4.0 + stsfld int32 FieldTestsType::StaticInitonlyField + ret + } +} + +.class public auto ansi beforefieldinit OtherType + extends [System.Runtime]System.Object +{ + .field public static class OtherType Instance + + .field public initonly int32 InstanceInitonlyField + .field public static initonly int32 StaticInitonlyField + + .method public hidebysig instance void 'special.LdfldStlfdInitonlyCctor..cctor_Invalid_Initonly.Initonly'() cil managed { ret } + .method public hidebysig specialname rtspecialname instance void .cctor() cil managed + { + ldsfld class OtherType OtherType::Instance + ldflda int32 OtherType::InstanceInitonlyField + pop + ldsfld class OtherType OtherType::Instance + ldc.i4.0 + stfld int32 OtherType::InstanceInitonlyField + ret + } +} |