Weaving adds reference to System.Private.CoreLib - Roslyn doesn't like that
Hello, we are using MrAdvice on one of our assemblies. The aspect gets woven in, the assembly runs fine. Great!
Environment: dotnet 8 with MrAdvice 2.19.1 nuget
But after this dll runs through Dotfuscator and then is used as a referenceassembly in a Roslyn compilation call (we have to generate additional dlls at the clients site after deploying), we get a compile error
(31,9): error CS0012: The type "Object" is defined in an assembly that is not referenced. Add a reference to the assembly "System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e".
Roslyn does not complain when given an unwoven dotfuscated version of the dll. The difference is the additional reference to System.Private.CoreLib, that MrAdvide apparently adds. Why does it do that? Referencing the System.Runtime should be enough from what I understand.
Can you avoid generating that additional reference or tell us a trick to avoid it? Any hint appreciated.
Thank you and regards, Frank
Hi, sorry about that, I’ll take a look at it. However this problem rings a bell and I am not sure whether it can be solved. I’ll let you know.
We investigated the issue further. After using ildasm.exe to disassemble the code, we located the offending code. Here is the IL code for a typical example:
.method /*060003A4*/ public hidebysig newslot virtual
instance void Validate(!TDomainRootObject domainObject) cil managed
// SIG: 20 01 01 13 00
{
// Method begins at RVA 0x11750
// Code size 61 (0x3d)
.maxstack 8
.locals /*1100002F*/ init (object[] V_0,
class [System.Private.CoreLib/*2300003A*/]System.Type/*0100024E*/[] V_1)
IL_0000: /* 02 | */ ldarg.0
IL_0001: /* 17 | */ ldc.i4.1
IL_0002: /* 8D | (01)000002 */ newarr [System.Runtime/*23000001*/]System.Object/*01000002*/
IL_0007: /* 0A | */ stloc.0
IL_0008: /* 06 | */ ldloc.0
IL_0009: /* 16 | */ ldc.i4.0
IL_000a: /* 03 | */ ldarg.1
IL_000b: /* 8C | (1B)00008C */ box !TDomainRootObject/*1B00008C*/
IL_0010: /* A2 | */ stelem.ref
IL_0011: /* 06 | */ ldloc.0
IL_0012: /* D0 | (06)0003A4 */ ldtoken method instance void Fs.Ikaros.Core.Base.Logic.TypedPersistableManagerBase`1/*02000075*/::Validate(!TDomainRootObject) /* 060003A4 */
IL_0017: /* D0 | (06)0003A9 */ ldtoken method instance void Fs.Ikaros.Core.Base.Logic.TypedPersistableManagerBase`1/*02000075*/::'Validateï'(!TDomainRootObject) /* 060003A9 */
IL_001c: /* D0 | (02)000075 */ ldtoken Fs.Ikaros.Core.Base.Logic.TypedPersistableManagerBase`1/*02000075*/
IL_0021: /* 17 | */ ldc.i4.1
IL_0022: /* 8D | (01)00024E */ newarr [System.Private.CoreLib/*2300003A*/]System.Type/*0100024E*/
IL_0027: /* 0B | */ stloc.1
IL_0028: /* 07 | */ ldloc.1
IL_0029: /* 16 | */ ldc.i4.0
IL_002a: /* D0 | (1B)00008C */ ldtoken !TDomainRootObject/*1B00008C*/
IL_002f: /* 28 | (0A)000174 */ call class [System.Private.CoreLib/*2300003A*/]System.Type/*0100024E*/ [System.Private.CoreLib/*2300003A*/]System.Type/*0100024E*/::GetTypeFromHandle(valuetype [System.Private.CoreLib/*2300003A*/]System.RuntimeTypeHandle/*0100024F*/) /* 0A000174 */
IL_0034: /* A2 | */ stelem.ref
IL_0035: /* 07 | */ ldloc.1
IL_0036: /* 28 | (06)001417 */ call object ArxOne.MrAdvice.'?Invocation'/*02000437*/::ProceedAspect(object,
object[],
valuetype [System.Runtime/*23000001*/]System.RuntimeMethodHandle/*010001DC*/,
valuetype [System.Runtime/*23000001*/]System.RuntimeMethodHandle/*010001DC*/,
valuetype [System.Runtime/*23000001*/]System.RuntimeTypeHandle/*010001DD*/,
class [System.Runtime/*23000001*/]System.Type/*0100000B*/[]) /* 06001417 */
IL_003b: /* 26 | */ pop
IL_003c: /* 2A | */ ret
} // end of method TypedPersistableManagerBase`1::Validate
The problem is that in the places marked in bold, the types System.Type and System.RuntimeTypeHandle incorrectly refer to System.Private.CoreLib/*2300003A*/ instead of System.Runtime/*23000001*/ and so a reference to System.Private.CoreLib is added to the assembly at the end. Interestingly, everything is correct when ProceedAspect is called. All other code locations are analogue and only concern System.Type and the method Type.GetTypeFromHandle thereof.
As a trial, we changed all occurrences of System.Private.CoreLib:2300003A in the IL code to System.Runtime:23000001, removed the reference to System.Private.CoreLib and recompiled with ilasm.exe. Everything worked as expected, so we are on the right track.
The problematic code appears to be generated in the WeaveInfoAdvices and GetGenericParametersArgument methods of the ArxOne.MrAdvice.Weaver.AspectWeaver class.
This part of the code seems to determine the wrong assembly System.Private.CoreLib for System.Type:
private static InvocationArgument GetGenericParametersArgument(MethodDef method)
{
...
var genericParametersVariable = hasGeneric
? new Local(new SZArraySig(method.Module.SafeImport(typeof(Type)).ToTypeSig())) { Name = "genericParameters" }
: null;
...
}
And these two parts seem to determine the incorrect assembly System.Private.CoreLib for the method Type.GetTypeFromHandle, including its parameter and return value:
private static InvocationArgument GetGenericParametersArgument(MethodDef method)
{
...
instructions.Emit(OpCodes.Call, ReflectionUtility.GetMethodInfo(() => Type.GetTypeFromHandle(new RuntimeTypeHandle())));
...
}
private void WeaveInfoAdvices(TypeDef infoAdvisedType, ModuleDef moduleDefinition, bool useWholeAssembly)
{
...
var getTypeFromHandleMethodInfo = ReflectionUtility.GetMethodInfo(() => Type.GetTypeFromHandle(new RuntimeTypeHandle()));
instructions.Emit(OpCodes.Call, moduleDefinition.SafeImport(getTypeFromHandleMethodInfo));
...
}
We hope that this initial analysis will help you to fix the issue. Unfortunately, we have now reached the point where we lack in-depth knowledge of IL code generation and dnlib, so we are stuck here.