MrAdvice icon indicating copy to clipboard operation
MrAdvice copied to clipboard

Weaving adds reference to System.Private.CoreLib - Roslyn doesn't like that

Open FS-FrankLakmann opened this issue 7 months ago • 2 comments

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

FS-FrankLakmann avatar May 22 '25 14:05 FS-FrankLakmann

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.

picrap avatar May 27 '25 20:05 picrap

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.

fsket avatar Jun 11 '25 13:06 fsket