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-10-19 20:48:11 +0300
committerJan Kotas <jkotas@microsoft.com>2017-10-19 20:48:11 +0300
commit4d4d738ab3f3c558b297d2d5481fc6e4b4f8a7f9 (patch)
tree114f9635ff65544b9948ebbe7ac8ee400349f80f /src/ILVerify
parent65209c45e21aeb73351459480ecbc7756642b73b (diff)
[ILVerify] Implement type / method / field access verifications (#4762)
* WIP: Implemented class and method access verification. * Changed access verifications to appropriately cast to EcmaType/Method. * Added test cases for type / method access verifications. * Implemented method signature access verification. * Added test cases for method signature access verification. * Implemented field access verification. * Added tests for field access verification. * Added special test case for accessing family field of superclass of containing class. Refactored some AccessTest names. * Added additional instance parameter to field/method access checks, to check family access. * Implemented access verification for friend assemblies. * Added relevant PEVerify code part for security critical code. * Added try-catch to public key comparison.
Diffstat (limited to 'src/ILVerify')
-rw-r--r--src/ILVerify/src/AccessVerificationHelpers.cs345
-rw-r--r--src/ILVerify/src/ILImporter.Verify.cs48
-rw-r--r--src/ILVerify/src/ILVerify.csproj1
-rw-r--r--src/ILVerify/src/Resources/Strings.resx6
-rw-r--r--src/ILVerify/src/VerifierError.cs4
-rw-r--r--src/ILVerify/tests/ILTests/AccessTests.il398
-rw-r--r--src/ILVerify/tests/ILTests/AccessTestsExtern.il152
-rw-r--r--src/ILVerify/tests/ILTests/AccessTestsFriend.il26
-rw-r--r--src/ILVerify/tests/TestDataLoader.cs4
9 files changed, 966 insertions, 18 deletions
diff --git a/src/ILVerify/src/AccessVerificationHelpers.cs b/src/ILVerify/src/AccessVerificationHelpers.cs
new file mode 100644
index 000000000..c2345b137
--- /dev/null
+++ b/src/ILVerify/src/AccessVerificationHelpers.cs
@@ -0,0 +1,345 @@
+// 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.
+
+using System;
+using System.Diagnostics;
+using System.Reflection;
+using Internal.TypeSystem;
+using Internal.TypeSystem.Ecma;
+
+namespace ILVerify
+{
+ internal static class AccessVerificationHelpers
+ {
+ /// <summary>
+ /// Returns whether the class <paramref name="currentClass"/> can access the class <paramref name="targetClass"/>.
+ /// </summary>
+ internal static bool CanAccess(this TypeDesc currentClass, TypeDesc targetClass)
+ {
+ if (targetClass.IsGenericParameter || targetClass.IsSignatureVariable)
+ return true; // Generic parameters are always accessible
+
+ if (targetClass.IsParameterizedType)
+ return currentClass.CanAccess(((ParameterizedType)targetClass).ParameterType);
+
+#if false
+ // perform transparency check on the type, if the caller is transparent
+ if ((NULL != pCurrentMD) && Security::IsTransparentMethod(pCurrentMD))
+ {
+ // check if type is visible outside the assembly
+ if (!IsTypeVisibleOutsideAssembly(pTargetClass))
+ {
+ // check transparent/critical on type
+ if (!Security::CheckNonPublicCriticalAccess(pCurrentMD, NULL, NULL, pTargetClass))
+ return FALSE;
+ }
+ }
+#endif
+
+ // Check access to class instantiations if generic class
+ if (targetClass.HasInstantiation && !currentClass.CanAccessInstantiation(targetClass.Instantiation))
+ return false;
+
+ var currentTypeDef = (MetadataType)currentClass.GetTypeDefinition();
+ var targetTypeDef = (EcmaType)targetClass.GetTypeDefinition();
+
+ var targetContainingType = targetTypeDef.ContainingType;
+ if (targetContainingType == null)
+ {
+ // a non-nested class can be either all public or accessible only from its own assembly (and friends)
+ if ((targetTypeDef.Attributes & TypeAttributes.Public) != 0)
+ return true;
+ else
+ return currentTypeDef.Module == targetTypeDef.Module || targetTypeDef.Module.GrantsFriendAccessTo(currentTypeDef.Module);
+ }
+
+ // Target class is nested
+ MethodAttributes visibility = NestedToMethodAccessAttribute(targetTypeDef.Attributes);
+
+ // Translate access check into member access check, i.e. check whether the current class can access
+ // a member of the enclosing class with the visibility of target class
+ return currentTypeDef.CanAccessMember(targetContainingType, visibility, null);
+ }
+
+ /// <summary>
+ /// Returns whether the class '<paramref name="currentClass"/>' can access the method '<paramref name="targetMethod"/>' through
+ /// the instance '<paramref name="instance"/>'. The instance can be null, if the method to be accessed is static.
+ /// </summary>
+ internal static bool CanAccess(this TypeDesc currentType, MethodDesc targetMethod, TypeDesc instance = null)
+ {
+ // If generic method, check instantiation access
+ if (targetMethod.HasInstantiation && !currentType.CanAccessInstantiation(targetMethod.Instantiation))
+ return false;
+
+ var targetMethodDef = (EcmaMethod)targetMethod.GetTypicalMethodDefinition();
+ var currentTypeDef = (MetadataType)currentType.GetTypeDefinition();
+
+ if (!currentTypeDef.CanAccessMember(targetMethod.OwningType, targetMethodDef.Attributes & MethodAttributes.MemberAccessMask, instance))
+ return false;
+
+ return currentTypeDef.CanAccessMethodSignature(targetMethod);
+ }
+
+ /// <summary>
+ /// Returns whether the class '<paramref name="currentClass"/>' can access the field '<paramref name="targetField"/>' through
+ /// the instance '<paramref name="instance"/>'. The instance can be null, if the field to be accessed is static.
+ /// </summary>
+ internal static bool CanAccess(this TypeDesc currentType, FieldDesc targetField, TypeDesc instance = null)
+ {
+ // Check access to field owning type
+ var targetFieldDef = (EcmaField)targetField.GetTypicalFieldDefinition();
+ var currentTypeDef = (MetadataType)currentType.GetTypeDefinition();
+
+ var targetFieldAccess = FieldToMethodAccessAttribute(targetFieldDef.Attributes);
+
+ if (!currentTypeDef.CanAccessMember(targetField.OwningType, targetFieldAccess, instance))
+ return false;
+
+ // Check access to field type itself
+ return currentType.CanAccess(targetField.FieldType);
+ }
+
+ private static bool CanAccessMember(this MetadataType currentType, TypeDesc targetType, MethodAttributes memberVisibility, TypeDesc instance)
+ {
+ if (instance == null)
+ instance = currentType;
+
+ // Check access to class defining member
+ if (!currentType.CanAccess(targetType))
+ return false;
+
+ var targetTypeDef = (MetadataType)targetType.GetTypeDefinition();
+
+ if (memberVisibility == MethodAttributes.Public)
+ return true;
+
+ // This is module-scope checking, to support C++ file & function statics.
+ if (memberVisibility == MethodAttributes.PrivateScope)
+ return currentType.Module == targetTypeDef.Module;
+
+ if (memberVisibility == MethodAttributes.Assembly)
+ return currentType.Module == targetTypeDef.Module || targetTypeDef.Module.GrantsFriendAccessTo(currentType.Module);
+
+ if (memberVisibility == MethodAttributes.FamANDAssem)
+ {
+ if (currentType.Module != targetTypeDef.Module && !targetTypeDef.Module.GrantsFriendAccessTo(currentType.Module))
+ return false;
+ }
+
+ // Nested classes can access all members of their parent class.
+ do
+ {
+ // Classes have access to all of their own members
+ if (currentType == targetTypeDef)
+ return true;
+
+ switch (memberVisibility)
+ {
+ case MethodAttributes.FamORAssem:
+ if (currentType.Module == targetTypeDef.Module || targetTypeDef.Module.GrantsFriendAccessTo(currentType.Module))
+ return true;
+
+ // Check if current class is subclass of target
+ if (CanAccessFamily(currentType, targetTypeDef, instance))
+ return true;
+ break;
+ case MethodAttributes.Family:
+ case MethodAttributes.FamANDAssem:
+ // Assembly acces was already checked earlier, so only need to check family access
+ if (CanAccessFamily(currentType, targetTypeDef, instance))
+ return true;
+ break;
+ case MethodAttributes.Private:
+ break; // Already handled by loop
+ default:
+ Debug.Assert(false);
+ break;
+ }
+
+ var containingType = currentType.ContainingType;
+ if (containingType != null)
+ currentType = (MetadataType)containingType.GetTypeDefinition();
+ else
+ currentType = null;
+ } while (currentType != null);
+
+ return false;
+ }
+
+ private static bool CanAccessInstantiation(this TypeDesc currentType, Instantiation instantiation)
+ {
+ foreach (var inst in instantiation)
+ {
+ if (!currentType.CanAccess(inst))
+ return false;
+ }
+
+ return true;
+ }
+
+ private static bool CanAccessMethodSignature(this TypeDesc currentType, MethodDesc targetMethod)
+ {
+ var methodSig = targetMethod.Signature;
+
+ // Check return type
+ var returnType = methodSig.ReturnType;
+ if (returnType.IsParameterizedType)
+ returnType = ((ParameterizedType)returnType).ParameterType;
+
+ if (!returnType.IsGenericParameter && !returnType.IsSignatureVariable // Generic parameters are always accessible
+ && !returnType.IsVoid)
+ {
+ if (!currentType.CanAccess(returnType))
+ return false;
+ }
+
+ // Check arguments
+ for (int i = 0; i < methodSig.Length; ++i)
+ {
+ var param = methodSig[i];
+ if (param.IsByRef)
+ param = ((ByRefType)param).ParameterType;
+
+ if (param.IsGenericParameter || param.IsSignatureVariable)
+ continue; // Generic parameters are always accessible
+
+ if (!currentType.CanAccess(param))
+ return false;
+ }
+
+ return true;
+ }
+
+ private static bool CanAccessFamily(TypeDesc currentType, TypeDesc targetTypeDef, TypeDesc instanceType)
+ {
+ // Iterate through all containing types of instance
+ while (instanceType != null)
+ {
+ var curInstTypeDef = instanceType;
+ var currentTypeDef = currentType.GetTypeDefinition();
+ // Iterate through all super types of current instance type
+ while (curInstTypeDef != null)
+ {
+ if (currentTypeDef == curInstTypeDef.GetTypeDefinition())
+ {
+ // At this point we know that the instance type is able to access the same family fields as current type
+ // Now iterate through all super types of current type to see if current type can access family target type
+ while (currentTypeDef != null)
+ {
+ if (currentTypeDef == targetTypeDef)
+ return true;
+
+ currentTypeDef = currentTypeDef.BaseType;
+ if (currentTypeDef != null)
+ currentTypeDef = currentTypeDef.GetTypeDefinition();
+ }
+
+ return false;
+ }
+
+ curInstTypeDef = curInstTypeDef.BaseType;
+ }
+
+ instanceType = ((MetadataType)instanceType.GetTypeDefinition()).ContainingType;
+ }
+
+ return false;
+ }
+
+ private const string PUBLIC_KEY = "PublicKey=";
+
+ private static bool GrantsFriendAccessTo(this ModuleDesc module, ModuleDesc friendModule)
+ {
+ var assembly = (EcmaAssembly)module;
+ var friendAssembly = (IAssemblyDesc)friendModule;
+
+ var friendName = friendAssembly.GetName();
+ var friendPublicKey = friendName.GetPublicKey();
+
+ foreach (var attribute in assembly.GetDecodedCustomAttributes("System.Runtime.CompilerServices", "InternalsVisibleToAttribute"))
+ {
+ var friendValues = ((string)attribute.FixedArguments[0].Value).Split(", ");
+ if (friendValues.Length >= 1 && friendValues.Length <= 2)
+ {
+ if (friendValues[0] != friendName.Name)
+ continue;
+
+ if (friendValues.Length == 2 &&
+ (!friendValues[1].StartsWith(PUBLIC_KEY) || !IsSamePublicKey(friendPublicKey, friendValues[1].Substring(PUBLIC_KEY.Length))))
+ continue;
+
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static bool IsSamePublicKey(byte[] key1, string key2)
+ {
+ if (key1.Length * 2 != key2.Length)
+ return false;
+
+ for (int i = 0; i < key1.Length; i++)
+ {
+ try
+ {
+ if (key1[i] != Convert.ToByte(key2[i * 2] + "" + key2[i * 2 + 1], 16))
+ return false;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private static MethodAttributes NestedToMethodAccessAttribute(TypeAttributes nestedVisibility)
+ {
+ switch (nestedVisibility & TypeAttributes.VisibilityMask)
+ {
+ case TypeAttributes.NestedAssembly:
+ return MethodAttributes.Assembly;
+ case TypeAttributes.NestedFamANDAssem:
+ return MethodAttributes.FamANDAssem;
+ case TypeAttributes.NestedFamily:
+ return MethodAttributes.Family;
+ case TypeAttributes.NestedFamORAssem:
+ return MethodAttributes.FamORAssem;
+ case TypeAttributes.NestedPrivate:
+ return MethodAttributes.Private;
+ case TypeAttributes.NestedPublic:
+ return MethodAttributes.Public;
+ default:
+ Debug.Assert(false);
+ return MethodAttributes.Public;
+ }
+ }
+
+ private static MethodAttributes FieldToMethodAccessAttribute(FieldAttributes attributes)
+ {
+ switch (attributes & FieldAttributes.FieldAccessMask)
+ {
+ case FieldAttributes.Assembly:
+ return MethodAttributes.Assembly;
+ case FieldAttributes.FamANDAssem:
+ return MethodAttributes.FamANDAssem;
+ case FieldAttributes.Family:
+ return MethodAttributes.Family;
+ case FieldAttributes.FamORAssem:
+ return MethodAttributes.FamORAssem;
+ case FieldAttributes.Private:
+ return MethodAttributes.Private;
+ case FieldAttributes.PrivateScope:
+ return MethodAttributes.PrivateScope;
+ case FieldAttributes.Public:
+ return MethodAttributes.Public;
+ default:
+ Debug.Assert(false);
+ return MethodAttributes.Public;
+ }
+ }
+ }
+}
diff --git a/src/ILVerify/src/ILImporter.Verify.cs b/src/ILVerify/src/ILImporter.Verify.cs
index 980f718c7..41ce6434a 100644
--- a/src/ILVerify/src/ILImporter.Verify.cs
+++ b/src/ILVerify/src/ILImporter.Verify.cs
@@ -1207,6 +1207,8 @@ again:
}
}
+ TypeDesc instance = null;
+
if (opcode == ILOpcode.newobj)
{
// TODO:
@@ -1215,6 +1217,7 @@ again:
if (methodType != null)
{
var actualThis = Pop(allowUninitThis: true);
+ instance = actualThis.Type;
var declaredThis = methodType.IsValueType ?
StackValue.CreateByRef(methodType) : StackValue.CreateObjRef(methodType);
@@ -1294,16 +1297,8 @@ again:
VerificationError(VerifierError.UnsatisfiedMethodParentInst, method.OwningType);
else if (!method.CheckConstraints(_instantiationContext))
VerificationError(VerifierError.UnsatisfiedMethodInst, method);
-#if false
- // Access verifications
- handleMemberAccessForVerification(callInfo.accessAllowed, callInfo.callsiteCalloutHelper,
- MVER_E_METHOD_ACCESS);
- if (mflags & CORINFO_FLG_PROTECTED)
- {
- Verify(m_jitInfo->canAccessFamily(getCurrentMethodHandle(), instanceClassHnd), MVER_E_METHOD_ACCESS);
- }
-#endif
+ Check(_method.OwningType.CanAccess(method, instance), VerifierError.MethodAccess);
TypeDesc returnType = sig.ReturnType;
@@ -1375,9 +1370,13 @@ again:
NO_WAY("Currently do not support LDFTN of Parameterized functions");
#endif
+ TypeDesc instance;
+
if (opCode == ILOpcode.ldftn)
{
_delegateCreateStart = _currentInstructionOffset;
+
+ instance = null;
}
else if (opCode == ILOpcode.ldvirtftn)
{
@@ -1393,6 +1392,7 @@ again:
declaredType = StackValue.CreateFromType(method.OwningType);
var thisPtr = Pop();
+ instance = thisPtr.Type;
CheckIsObjRef(thisPtr);
CheckIsAssignable(thisPtr, declaredType);
@@ -1409,13 +1409,7 @@ again:
else if (!method.CheckConstraints(_instantiationContext))
VerificationError(VerifierError.UnsatisfiedMethodInst, method);
-#if false
- Verify(m_jitInfo->canAccessMethod(getCurrentMethodHandle(), //from
- methodClassHnd, // in
- methHnd, // what
- instanceClassHnd),
- MVER_E_METHOD_ACCESS);
-#endif
+ Check(_method.OwningType.CanAccess(method, instance), VerifierError.MethodAccess);
Push(StackValue.CreateMethod(method));
}
@@ -1683,9 +1677,13 @@ again:
var field = ResolveFieldToken(token);
+ TypeDesc instance;
+
if (isStatic)
{
Check(field.IsStatic, VerifierError.ExpectedStaticField);
+
+ instance = null;
}
else
{
@@ -1702,8 +1700,12 @@ again:
StackValue.CreateByRef(owningType) : StackValue.CreateObjRef(owningType);
CheckIsAssignable(actualThis, declaredThis);
+
+ instance = actualThis.Type;
}
+ Check(_method.OwningType.CanAccess(field, instance), VerifierError.FieldAccess);
+
Push(StackValue.CreateFromType(field.FieldType));
}
@@ -1712,11 +1714,14 @@ again:
var field = ResolveFieldToken(token);
bool isPermanentHome = false;
+ TypeDesc instance;
+
if (isStatic)
{
Check(field.IsStatic, VerifierError.ExpectedStaticField);
isPermanentHome = true;
+ instance = null;
}
else
{
@@ -1735,8 +1740,11 @@ again:
CheckIsAssignable(actualThis, declaredThis);
isPermanentHome = actualThis.Kind == StackValueKind.ObjRef || actualThis.IsPermanentHome;
+ instance = actualThis.Type;
}
+ Check(_method.OwningType.CanAccess(field, instance), VerifierError.FieldAccess);
+
Push(StackValue.CreateByRef(field.FieldType, false, isPermanentHome));
}
@@ -1749,9 +1757,13 @@ again:
var field = ResolveFieldToken(token);
+ TypeDesc instance;
+
if (isStatic)
{
Check(field.IsStatic, VerifierError.ExpectedStaticField);
+
+ instance = null;
}
else
{
@@ -1768,8 +1780,12 @@ again:
StackValue.CreateByRef(owningType) : StackValue.CreateObjRef(owningType);
CheckIsAssignable(actualThis, declaredThis);
+
+ instance = actualThis.Type;
}
+ Check(_method.OwningType.CanAccess(field, instance), VerifierError.FieldAccess);
+
CheckIsAssignable(value, StackValue.CreateFromType(field.FieldType));
}
diff --git a/src/ILVerify/src/ILVerify.csproj b/src/ILVerify/src/ILVerify.csproj
index 0a7950bab..615183886 100644
--- a/src/ILVerify/src/ILVerify.csproj
+++ b/src/ILVerify/src/ILVerify.csproj
@@ -17,6 +17,7 @@
<Compile Include="SimpleTypeSystemContext.cs" />
<Compile Include="VerifierError.cs" />
<Compile Include="TypeSystemHelpers.cs" />
+ <Compile Include="AccessVerificationHelpers.cs" />
</ItemGroup>
<ItemGroup>
diff --git a/src/ILVerify/src/Resources/Strings.resx b/src/ILVerify/src/Resources/Strings.resx
index 868a917fb..543e9b44f 100644
--- a/src/ILVerify/src/Resources/Strings.resx
+++ b/src/ILVerify/src/Resources/Strings.resx
@@ -207,6 +207,9 @@
<data name="ExpectedValClassObjRefVariable" xml:space="preserve">
<value>Value type, ObjRef type or variable type expected.</value>
</data>
+ <data name="FieldAccess" xml:space="preserve">
+ <value>Field is not visible.</value>
+ </data>
<data name="InitLocals" xml:space="preserve">
<value>initlocals must be set for verifiable methods with one or more local variables.</value>
</data>
@@ -219,6 +222,9 @@
<data name="LdvirtftnOnStatic" xml:space="preserve">
<value>ldvirtftn on static.</value>
</data>
+ <data name="MethodAccess" xml:space="preserve">
+ <value>Method is not visible.</value>
+ </data>
<data name="PathStackDepth" xml:space="preserve">
<value>Stack depth differs depending on path.</value>
</data>
diff --git a/src/ILVerify/src/VerifierError.cs b/src/ILVerify/src/VerifierError.cs
index 33862ef92..df2f02329 100644
--- a/src/ILVerify/src/VerifierError.cs
+++ b/src/ILVerify/src/VerifierError.cs
@@ -131,8 +131,8 @@ 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."
- //E_METHOD_ACCESS "Method is not visible."
- //E_FIELD_ACCESS "Field is not visible."
+ MethodAccess, // Method is not visible.
+ FieldAccess, // Field is not visible.
//E_DEAD "Item is unusable at this point."
ExpectedStaticField, // Expected static field.
//E_FIELD_NO_STATIC "Expected non-static field."
diff --git a/src/ILVerify/tests/ILTests/AccessTests.il b/src/ILVerify/tests/ILTests/AccessTests.il
new file mode 100644
index 000000000..9de153c3c
--- /dev/null
+++ b/src/ILVerify/tests/ILTests/AccessTests.il
@@ -0,0 +1,398 @@
+// 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 extern AccessTestsFriend
+{
+}
+
+.assembly AccessTests
+{
+}
+
+.class private auto ansi beforefieldinit PrivateClass
+{
+ .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
+ {
+ ldarg.0
+ call instance void [System.Runtime]System.Object::.ctor()
+ ret
+ }
+}
+
+.class public auto ansi beforefieldinit GenericClass<S, T>
+ extends [System.Runtime]System.Object
+{
+ .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
+ {
+ ldarg.0
+ call instance void [System.Runtime]System.Object::.ctor()
+ ret
+ }
+}
+
+.class public auto ansi beforefieldinit SimpleClass
+ extends [System.Runtime]System.Object
+{
+ .field public static int32 publicField
+ .field private static int32 privateField
+ .field family static int32 familyField
+ .field assembly static int32 assemblyField
+ .field famorassem static int32 familyOrAssemblyField
+ .field famandassem static int32 familyAndAssemblyField
+
+ .field family int32 instanceFamilyField
+
+ .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
+ {
+ ldarg.0
+ call instance void [System.Runtime]System.Object::.ctor()
+ ret
+ }
+
+ .method private hidebysig static void PrivateMethod() cil managed
+ {
+ ret
+ }
+
+ .method family hidebysig static void FamilyMethod() cil managed
+ {
+ ret
+ }
+
+ .method assembly hidebysig static void AssemblyMethod() cil managed
+ {
+ ret
+ }
+
+ .method famorassem hidebysig static void FamilyOrAssemblyMethod() cil managed
+ {
+ ret
+ }
+
+ .method famandassem hidebysig static void FamilyAndAssemblyMethod() cil managed
+ {
+ ret
+ }
+
+ .method public hidebysig static void InaccessibleParamMethod(class SimpleClass/PrivateNestedClass c) cil managed
+ {
+ ret
+ }
+
+ .method public hidebysig static void GenericMethod<T>() cil managed
+ {
+ ret
+ }
+
+ .method family hidebysig instance void FamilyMethod() cil managed
+ {
+ ret
+ }
+
+ .method public hidebysig static class SimpleClass/PrivateNestedClass InaccessibleReturnMethod() cil managed
+ {
+ newobj instance void SimpleClass/PrivateNestedClass::.ctor()
+ ret
+ }
+
+ .class nested public auto ansi beforefieldinit PublicNestedClass
+ extends [System.Runtime]System.Object
+ {
+ .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
+ {
+ ldarg.0
+ call instance void [System.Runtime]System.Object::.ctor()
+ ret
+ }
+
+ .method public hidebysig static void Instantiate.PrivateNestedClassFromNested_Valid() cil managed
+ {
+ newobj instance void SimpleClass/PrivateNestedClass::.ctor()
+ pop
+ ret
+ }
+
+ .method public hidebysig static void Load.PrivateFieldFromNestedClass_Valid() cil managed
+ {
+ ldsfld int32 SimpleClass::privateField
+ pop
+ ret
+ }
+ }
+
+ .class nested private auto ansi beforefieldinit PrivateNestedClass
+ extends [System.Runtime]System.Object
+ {
+ .field public static int32 publicField
+
+ .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
+ {
+ ldarg.0
+ call instance void [System.Runtime]System.Object::.ctor()
+ ret
+ }
+ }
+
+ .class nested assembly auto ansi beforefieldinit AssemblyNestedClass
+ extends [System.Runtime]System.Object
+ {
+ .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
+ {
+ ldarg.0
+ call instance void [System.Runtime]System.Object::.ctor()
+ ret
+ }
+ }
+
+ .class nested famorassem auto ansi beforefieldinit FamilyOrAssemblyNestedClass
+ extends [System.Runtime]System.Object
+ {
+ .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
+ {
+ ldarg.0
+ call instance void [System.Runtime]System.Object::.ctor()
+ ret
+ }
+ }
+
+ .class nested famandassem auto ansi beforefieldinit FamilyAndAssemblyNestedClass
+ extends [System.Runtime]System.Object
+ {
+ .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
+ {
+ ldarg.0
+ call instance void [System.Runtime]System.Object::.ctor()
+ ret
+ }
+ }
+
+ .class nested family auto ansi beforefieldinit FamilyNestedClass
+ extends [System.Runtime]System.Object
+ {
+ .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
+ {
+ ldarg.0
+ call instance void [System.Runtime]System.Object::.ctor()
+ ret
+ }
+ }
+
+ .method private hidebysig static void Call.PrivateClassParamIntern_Valid(class SimpleClass/PrivateNestedClass c) cil managed
+ {
+ ldarg.0
+ call void SimpleClass::InaccessibleParamMethod(class SimpleClass/PrivateNestedClass)
+ ret
+ }
+
+ .method private hidebysig static void Call.PrivateReturnTypeIntern_Valid() cil managed
+ {
+ call class SimpleClass/PrivateNestedClass SimpleClass::InaccessibleReturnMethod()
+ pop
+ ret
+ }
+}
+
+.class public auto ansi beforefieldinit AccessTestsType
+ extends [System.Runtime]System.Object
+{
+ .method public hidebysig instance void Instantiate.PublicNestedClass_Valid() cil managed
+ {
+ newobj instance void SimpleClass/PublicNestedClass::.ctor()
+ pop
+ ret
+ }
+
+ .method public hidebysig instance void Instantiate.PrivateNestedClass_Invalid_MethodAccess() cil managed
+ {
+ newobj instance void SimpleClass/PrivateNestedClass::.ctor()
+ pop
+ ret
+ }
+
+ .method public hidebysig instance void Instantiate.AssemNestedClass_Valid() cil managed
+ {
+ newobj instance void SimpleClass/AssemblyNestedClass::.ctor()
+ pop
+ ret
+ }
+
+ .method public hidebysig instance void Instantiate.AssemOrFamNestedClass_Valid() cil managed
+ {
+ newobj instance void SimpleClass/FamilyOrAssemblyNestedClass::.ctor()
+ pop
+ ret
+ }
+
+ .method public hidebysig instance void Instantiate.AssemAndFamNestedClass_Invalid_MethodAccess() cil managed
+ {
+ newobj instance void SimpleClass/FamilyAndAssemblyNestedClass::.ctor()
+ pop
+ ret
+ }
+
+ .method public hidebysig instance void Instantiate.FamilyNestedClass_Invalid_MethodAccess() cil managed
+ {
+ newobj instance void SimpleClass/FamilyNestedClass::.ctor()
+ pop
+ ret
+ }
+
+ .method public hidebysig instance void Instantiate.GenericWithPrivateNestedClass_Invalid_MethodAccess() cil managed
+ {
+ newobj instance void class GenericClass<class SimpleClass/PrivateNestedClass, class SimpleClass/PublicNestedClass>::.ctor()
+ pop
+ ret
+ }
+
+ .method public hidebysig instance void Call.PrivateClassParamExtern_Invalid_MethodAccess(class SimpleClass/PrivateNestedClass c) cil managed
+ {
+ ldarg.1
+ call void SimpleClass::InaccessibleParamMethod(class SimpleClass/PrivateNestedClass)
+ ret
+ }
+
+ .method public hidebysig instance void Call.PrivateReturnTypeExtern_Invalid_MethodAccess() cil managed
+ {
+ call class SimpleClass/PrivateNestedClass SimpleClass::InaccessibleReturnMethod()
+ pop
+ ret
+ }
+
+ .method public hidebysig instance void Call.GenericMethodWithPrivateNestedClass_Invalid_MethodAccess() cil managed
+ {
+ call void class SimpleClass::GenericMethod<class SimpleClass/PrivateNestedClass>()
+ ret
+ }
+
+ .method public hidebysig instance void Load.PrivateFieldExtern_Invalid_FieldAccess() cil managed
+ {
+ ldsfld int32 SimpleClass::privateField
+ pop
+ ret
+ }
+
+ .method public hidebysig instance void Load.PublicFieldOfPrivateClass_Invalid_FieldAccess() cil managed
+ {
+ ldsfld int32 SimpleClass/PrivateNestedClass::publicField
+ pop
+ ret
+ }
+}
+
+.class public auto ansi beforefieldinit DerivedType
+ extends SimpleClass
+{
+ .method public hidebysig instance void Call.DerivedFamAndAssemblyMethod_Valid() cil managed
+ {
+ call void SimpleClass::FamilyAndAssemblyMethod()
+ ret
+ }
+
+ .method public hidebysig instance void Instantiate.FamOrAssemblyNestedClassFromDerived_Valid() cil managed
+ {
+ newobj instance void SimpleClass/FamilyOrAssemblyNestedClass::.ctor()
+ pop
+ ret
+ }
+
+ .method public hidebysig instance void Instantiate.FamNestedClassFromDerived_Valid() cil managed
+ {
+ newobj instance void SimpleClass/FamilyNestedClass::.ctor()
+ pop
+ ret
+ }
+
+ .method private hidebysig instance void Load.FamFieldOfBaseWithBaseInstance_Invalid_FieldAccess(class SimpleClass c) cil managed
+ {
+ ldarg.1
+ ldfld int32 SimpleClass::instanceFamilyField
+ pop
+ ret
+ }
+
+ .method private hidebysig instance void Load.FamFieldOfBaseWithDerivedInstance_Valid() cil managed
+ {
+ ldarg.0
+ ldfld int32 SimpleClass::instanceFamilyField
+ pop
+ ret
+ }
+
+ .method private hidebysig instance void Call.FamMethodOfBaseWithBaseInstance_Invalid_MethodAccess(class SimpleClass c) cil managed
+ {
+ ldarg.1
+ call instance void SimpleClass::FamilyMethod()
+ ret
+ }
+
+ .method private hidebysig instance void Call.FamMethodOfBaseWithDerivedInstance_Valid() cil managed
+ {
+ ldarg.0
+ call instance void SimpleClass::FamilyMethod()
+ ret
+ }
+
+ .method private hidebysig instance void Load.AssemFieldOfFriendAssembly_Valid() cil managed
+ {
+ ldsfld int32 [AccessTestsFriend]AccessTestsFriendType::assemblyField
+ pop
+ ret
+ }
+
+ .method private hidebysig instance void Load.PrivateFieldOfFriendAssembly_Invalid_FieldAccess() cil managed
+ {
+ ldsfld int32 [AccessTestsFriend]AccessTestsFriendType::privateField
+ pop
+ ret
+ }
+}
+
+// Special case: Nested class trying to access family field of superclass of containing class
+
+.class private auto ansi beforefieldinit SuperClass
+ extends [System.Runtime]System.Object
+{
+ .field family static int32 familyField
+ .field family int32 instanceFamilyField
+
+ .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
+ {
+ ldarg.0
+ call instance void [System.Runtime]System.Object::.ctor()
+ ret
+ }
+}
+
+.class private auto ansi beforefieldinit NestedClass
+ extends SuperClass
+{
+ .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
+ {
+ ldarg.0
+ call instance void SuperClass::.ctor()
+ ret
+ }
+
+ .class nested private auto ansi beforefieldinit NestedClass
+ extends [System.Runtime]System.Object
+ {
+ .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
+ {
+ ldarg.0
+ call instance void [System.Runtime]System.Object::.ctor()
+ ret
+ }
+
+ .method private hidebysig instance void Load.FamFieldOfSuperOfContaining_Valid() cil managed
+ {
+ ldsfld int32 SuperClass::familyField
+ pop
+ ret
+ }
+ }
+}
diff --git a/src/ILVerify/tests/ILTests/AccessTestsExtern.il b/src/ILVerify/tests/ILTests/AccessTestsExtern.il
new file mode 100644
index 000000000..31be7b663
--- /dev/null
+++ b/src/ILVerify/tests/ILTests/AccessTestsExtern.il
@@ -0,0 +1,152 @@
+// 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 extern AccessTests
+{
+}
+
+.assembly AccessTestsExternal
+{
+}
+
+.class public auto ansi beforefieldinit AccessTestsType
+ extends [System.Runtime]System.Object
+{
+ .method public hidebysig instance void Instantiate.PublicClass_Valid() cil managed
+ {
+ newobj instance void [AccessTests]SimpleClass::.ctor()
+ pop
+ ret
+ }
+
+ .method public hidebysig instance void Instantiate.PrivateClass_Invalid_MethodAccess() cil managed
+ {
+ newobj instance void [AccessTests]PrivateClass::.ctor()
+ pop
+ ret
+ }
+
+ .method public hidebysig instance void Instantiate.PublicNested_Valid() cil managed
+ {
+ newobj instance void [AccessTests]SimpleClass/PublicNestedClass::.ctor()
+ pop
+ ret
+ }
+
+ .method public hidebysig instance void Instantiate.PrivateNested_Invalid_MethodAccess() cil managed
+ {
+ newobj instance void [AccessTests]SimpleClass/PrivateNestedClass::.ctor()
+ pop
+ ret
+ }
+
+ .method public hidebysig instance void Instantiate.AssemblyNested_Invalid_MethodAccess() cil managed
+ {
+ newobj instance void [AccessTests]SimpleClass/AssemblyNestedClass::.ctor()
+ pop
+ ret
+ }
+
+ .method public hidebysig instance void Instantiate.FamOrAssemNested_Invalid_MethodAccess() cil managed
+ {
+ newobj instance void [AccessTests]SimpleClass/FamilyOrAssemblyNestedClass::.ctor()
+ pop
+ ret
+ }
+
+ .method public hidebysig instance void Instantiate.FamAndAssemNested_Invalid_MethodAccess() cil managed
+ {
+ newobj instance void [AccessTests]SimpleClass/FamilyAndAssemblyNestedClass::.ctor()
+ pop
+ ret
+ }
+
+ .method public hidebysig instance void Instantiate.FamilyNested_Invalid_MethodAccess() cil managed
+ {
+ newobj instance void [AccessTests]SimpleClass/FamilyNestedClass::.ctor()
+ pop
+ ret
+ }
+
+ .method public hidebysig instance void Call.PrivateMethod_Invalid_MethodAccess() cil managed
+ {
+ call void [AccessTests]SimpleClass::PrivateMethod()
+ ret
+ }
+
+ .method public hidebysig instance void Call.FamilyMethod_Invalid_MethodAccess() cil managed
+ {
+ call void [AccessTests]SimpleClass::FamilyMethod()
+ ret
+ }
+
+ .method public hidebysig instance void Call.AssemblyMethod_Invalid_MethodAccess() cil managed
+ {
+ call void [AccessTests]SimpleClass::AssemblyMethod()
+ ret
+ }
+
+ .method public hidebysig instance void Call.FamOrAssemMethod_Invalid_MethodAccess() cil managed
+ {
+ call void [AccessTests]SimpleClass::FamilyOrAssemblyMethod()
+ ret
+ }
+
+ .method public hidebysig instance void Call.FamAndAssemMethod_Invalid_MethodAccess() cil managed
+ {
+ call void [AccessTests]SimpleClass::FamilyAndAssemblyMethod()
+ ret
+ }
+}
+
+.class public auto ansi beforefieldinit DerivedType
+ extends [AccessTests]SimpleClass
+{
+ .method public hidebysig instance void Call.DerivedFamMethod_Valid() cil managed
+ {
+ call void [AccessTests]SimpleClass::FamilyMethod()
+ ret
+ }
+
+ .method public hidebysig instance void Call.DerivedFamOrAssemMethod_Valid() cil managed
+ {
+ call void [AccessTests]SimpleClass::FamilyOrAssemblyMethod()
+ ret
+ }
+
+ .method public hidebysig instance void Call.DerivedFamAndAssemMethod_Invalid_MethodAccess() cil managed
+ {
+ call void [AccessTests]SimpleClass::FamilyAndAssemblyMethod()
+ ret
+ }
+}
+
+.class public auto ansi beforefieldinit DerivedClass
+ extends [AccessTests]SimpleClass
+{
+ .method public hidebysig instance void Instantiate.FamAndAssemNestedClassFromDerived_Invalid_MethodAccess() cil managed
+ {
+ newobj instance void [AccessTests]SimpleClass/FamilyAndAssemblyNestedClass::.ctor()
+ pop
+ ret
+ }
+
+ .method public hidebysig instance void Instantiate.FamOrAssemNestedClassFromDerived_Valid() cil managed
+ {
+ newobj instance void [AccessTests]SimpleClass/FamilyOrAssemblyNestedClass::.ctor()
+ pop
+ ret
+ }
+
+ .method public hidebysig instance void Instantiate.FamNestedClassFromDerived_Valid() cil managed
+ {
+ newobj instance void [AccessTests]SimpleClass/FamilyNestedClass::.ctor()
+ pop
+ ret
+ }
+}
diff --git a/src/ILVerify/tests/ILTests/AccessTestsFriend.il b/src/ILVerify/tests/ILTests/AccessTestsFriend.il
new file mode 100644
index 000000000..869470b62
--- /dev/null
+++ b/src/ILVerify/tests/ILTests/AccessTestsFriend.il
@@ -0,0 +1,26 @@
+// 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 extern AccessTests
+{
+}
+
+.assembly AccessTestsFriend
+{
+ // InternalsVisibleTo("AccessTests")
+ .custom instance void [System.Runtime]System.Runtime.CompilerServices.InternalsVisibleToAttribute::.ctor(string) = (
+ 01 00 0b 41 63 63 65 73 73 54 65 73 74 73 00 00
+ )
+}
+
+.class private auto ansi beforefieldinit AccessTestsFriendType
+ extends [System.Runtime]System.Object
+{
+ .field private static int32 privateField
+ .field assembly static int32 assemblyField
+}
diff --git a/src/ILVerify/tests/TestDataLoader.cs b/src/ILVerify/tests/TestDataLoader.cs
index d594aea12..15dc8efde 100644
--- a/src/ILVerify/tests/TestDataLoader.cs
+++ b/src/ILVerify/tests/TestDataLoader.cs
@@ -173,6 +173,10 @@ namespace ILVerify.Tests
{ systemRuntime.GetName().Name, systemRuntime.Location }
};
+ typeSystemContext.ReferenceFilePaths = new Dictionary<string, string>();
+ foreach (var fileName in GetAllTestDlls())
+ typeSystemContext.ReferenceFilePaths.Add(Path.GetFileNameWithoutExtension(fileName), TESTASSEMBLYPATH + fileName);
+
typeSystemContext.SetSystemModule(typeSystemContext.GetModuleForSimpleName(coreAssembly.GetName().Name));
return typeSystemContext.GetModuleFromPath(TESTASSEMBLYPATH + assemblyName);
}