3F / DllExport

.NET DllExport with .NET Core support (aka 3F/DllExport aka DllExport.bat)

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

DLL Export conflicts with Fody in Visual Studio 2015

OzzyL opened this issue · comments

commented

I recently upgraded from Visual Studio 2013 to 2015 and my projects where I used both DLL Export and Fody (More specifically ModuleInit.Fody) stopped working.

I have tried the same project on different computers with different versions of Visual Studio 2015. Same issue on all computers.

It seem as i can't use DLL Export together with Fody (e.g. ModuleInit). Both tools works great separately, but when both is included in a project the build fails.

The build error I get:

Severity    Code    Description Project File    Line    Suppression State
Error       C:\Users\[...]\AppData\Local\Temp\tmp4CC9\VCI_Comm_PlaybackNode.il(773) : error : Undeclared identifier IL_0055
D:\Projects\VCI_Project\trunk\VCI_Comm_Win\VCI_Comm_PlaybackNode\ConfigManager.cs(37) : error : syntax error at token ':' in:     IL_0055:  br.s       IL_0057  VCI_Comm_PlaybackNode   D:\Projects\VCI_Project\trunk\VCI_Comm_Win\packages\DllExport.1.4.0\tools\net.r_eg.DllExport.targets    61  

Using detailed buildlog I can see the following errors:

8>  calling 'C:\Windows\Microsoft.NET\Framework\v4.0.30319\ILAsm.exe' with /nologo "/out:D:\Projects\VCI_Project\trunk\VCI_Comm_Win\VCI_Comm_PlaybackNode\bin\x86\Debug\VCI_Comm_PlaybackNode.dll" "C:\Users\[...]\AppData\Local\Temp\tmp4CC9\VCI_Comm_PlaybackNode.il" /DLL "/resource=C:\Users\[...]\AppData\Local\Temp\tmp4CC9\VCI_Comm_PlaybackNode.res"  /debug   (TaskId:101)
8>  ILAsm 'C:\Windows\Microsoft.NET\Framework\v4.0.30319\ILAsm.exe' returned gracefully. (TaskId:101)
8>D:\Projects\VCI_Project\trunk\VCI_Comm_Win\packages\DllExport.1.4.0\tools\net.r_eg.DllExport.targets(61,5): error : C:\Users\[...]\AppData\Local\Temp\tmp4CC9\VCI_Comm_PlaybackNode.il(773) : error : Undeclared identifier IL_0055
8>D:\Projects\VCI_Project\trunk\VCI_Comm_Win\packages\DllExport.1.4.0\tools\net.r_eg.DllExport.targets(61,5): error : D:\Projects\VCI_Project\trunk\VCI_Comm_Win\VCI_Comm_PlaybackNode\ConfigManager.cs(37) : error : syntax error at token ':' in:     IL_0055:  br.s       IL_0057
8>D:\Projects\VCI_Project\trunk\VCI_Comm_Win\packages\DllExport.1.4.0\tools\net.r_eg.DllExport.targets(61,5): error : 
8>     at RGiesecke.DllExport.Parsing.IlParser.RunIlTool(String installPath, String toolFileName, String requiredPaths, String workingDirectory, String settingsName, String arguments, String toolLoggingCode, String verboseLoggingCode, IDllExportNotifier notifier, Int32 timeout, Func`2 suppressErrorOutputLine) in C:\Users\[...]\Downloads\DllExport-1.4\DllExport-1.4\RGiesecke.DllExport\Parsing\IlParser.cs:line 378
8>     at RGiesecke.DllExport.Parsing.IlAsm.RunCore(CpuPlatform cpu, String fileName, String ressourceParam, String ilSuffix) in C:\Users\[...]\Downloads\DllExport-1.4\DllExport-1.4\RGiesecke.DllExport\Parsing\ILAsm.cs:line 148
8>     at RGiesecke.DllExport.Parsing.IlAsm.Run(String outputFile, String ilSuffix, CpuPlatform cpu) in C:\Users\[...]\Downloads\DllExport-1.4\DllExport-1.4\RGiesecke.DllExport\Parsing\ILAsm.cs:line 118
8>     at RGiesecke.DllExport.Parsing.IlAsm.ReassembleFile(String outputFile, String ilSuffix, CpuPlatform cpu) in C:\Users\[...]\Downloads\DllExport-1.4\DllExport-1.4\RGiesecke.DllExport\Parsing\ILAsm.cs:line 80
8>     at RGiesecke.DllExport.DllExportWeaver.reassembleFile(IlAsm ilAsm, String outputFile, String ilSuffix, CpuPlatform cpu) in C:\Users\[...]\Downloads\DllExport-1.4\DllExport-1.4\RGiesecke.DllExport\DllExportWeaver.cs:line 196
8>     at RGiesecke.DllExport.DllExportWeaver.RunIlAsm(IlAsm ilAsm) in C:\Users\[...]\Downloads\DllExport-1.4\DllExport-1.4\RGiesecke.DllExport\DllExportWeaver.cs:line 147
8>     at RGiesecke.DllExport.DllExportWeaver.Run() in C:\Users\[...]\Downloads\DllExport-1.4\DllExport-1.4\RGiesecke.DllExport\DllExportWeaver.cs:line 87
8>     at RGiesecke.DllExport.MSBuild.ExportTaskImplementation`1.Execute() in C:\Users\[...]\Downloads\DllExport-1.4\DllExport-1.4\RGiesecke.DllExport.MSBuild\RGiesecke.DllExport.MSBuild\ExportTaskImplementation.cs:line 415 (TaskId:101)
8>Done executing task "DllExportAppDomainIsolatedTask" -- FAILED. (TaskId:101)
8>Done building target "DllExportMod" in project "VCI_Comm_PlaybackNode.csproj" -- FAILED.: (TargetId:172)
8>

I have tried both DLLExport v.1.2.7 and 1.4.0. Same issue with both.
I have also tried multiple versions of Fody. No difference.

A snippet from the generated .il file:

.class private auto ansi beforefieldinit 'VCI_Comm_PlaybackNode'.'ConfigManager'
       extends ['mscorlib']'System'.'Object'
{
  .field private class 'VCI_Comm_PlaybackNode.NodeConfig'.'CustomProperties' '_custProp'
  .field private class 'VCI_Comm_PlaybackNode.NodeConfig'.'CustomProperties' '<Config>k__BackingField'
  .custom instance void ['mscorlib']'System.Diagnostics'.'DebuggerBrowsableAttribute'::.ctor(valuetype ['mscorlib']'System.Diagnostics'.'DebuggerBrowsableState') = ( 01 00 00 00 00 00 00 00 ) 
  .custom instance void ['mscorlib']'System.Runtime.CompilerServices'.'CompilerGeneratedAttribute'::.ctor() = ( 01 00 00 00 ) 
  .method public hidebysig instance bool 
          'SetupConfig'(uint32 'sessionID',
                        string 'xmlConfig') cil managed
  {
    // Code size       106 (0x6a)
    .maxstack  3
    .locals init ([0] string 'key',
             [1] class ['System.Xml']'System.Xml.Serialization'.'XmlSerializer' 'serializer',
             [2] class ['mscorlib']'System.IO'.'StringReader' 'stream',
             [3] class ['System.Xml']'System.Xml'.'XmlReader' 'reader',
             [4] bool )
    .line 17,17 : 9,10 'C:\\Projects\\VCI_Project\\trunk\\VCI_Comm_Win\\VCI_Comm_PlaybackNode\\ConfigManager.cs'
    IL_0000:  nop
    .line 18,18 : 13,44 ''
    IL_0001:  ldarga.s   'sessionID'
    IL_0003:  call       instance string ['mscorlib']'System'.'UInt32'::'ToString'()
    IL_0008:  stloc.0
    .line 19,19 : 13,74 ''
    IL_0009:  ldtoken    'VCI_Comm_PlaybackNode.NodeConfig'.'CustomProperties'
    IL_000e:  call       class ['mscorlib']'System'.'Type' ['mscorlib']'System'.'Type'::'GetTypeFromHandle'(valuetype ['mscorlib']'System'.'RuntimeTypeHandle')
    IL_0013:  newobj     instance void ['System.Xml']'System.Xml.Serialization'.'XmlSerializer'::.ctor(class ['mscorlib']'System'.'Type')
    IL_0018:  stloc.1
    .line 21,21 : 20,60 ''
    IL_0019:  ldarg.2
    IL_001a:  newobj     instance void ['mscorlib']'System.IO'.'StringReader'::.ctor(string)
    IL_001f:  stloc.2
    .line 22,22 : 20,57 ''
    .try
    {
      IL_0020:  ldloc.2
      IL_0021:  call       class ['System.Xml']'System.Xml'.'XmlReader' ['System.Xml']'System.Xml'.'XmlReader'::'Create'(class ['mscorlib']'System.IO'.'TextReader')
      IL_0026:  stloc.3
      .line 23,23 : 13,14 ''
      .try
      {
        IL_0027:  nop
        .line 24,24 : 17,79 ''
        IL_0028:  ldarg.0
        IL_0029:  ldloc.1
        IL_002a:  ldloc.3
        IL_002b:  callvirt   instance object ['System.Xml']'System.Xml.Serialization'.'XmlSerializer'::'Deserialize'(class ['System.Xml']'System.Xml'.'XmlReader')
        IL_0030:  castclass  'VCI_Comm_PlaybackNode.NodeConfig'.'CustomProperties'
        IL_0035:  stfld      class 'VCI_Comm_PlaybackNode.NodeConfig'.'CustomProperties' 'VCI_Comm_PlaybackNode'.'ConfigManager'::'_custProp'
        .line 25,25 : 13,14 ''
        IL_003a:  nop
        IL_003b:  leave.s    IL_0048

        .line 16707566,16707566 : 0,0 ''
      }  // end .try
      finally
      {
        IL_003d:  ldloc.3
        IL_003e:  brfalse.s  IL_0047

        IL_0040:  ldloc.3
        IL_0041:  callvirt   instance void ['mscorlib']'System'.'IDisposable'::'Dispose'()
        IL_0046:  nop
        IL_0047:  endfinally
        .line 16707566,16707566 : 0,0 ''
      }  // end handler
      IL_0048:  leave.s    IL_0055

      .line 16707566,16707566 : 0,0 ''
    }  // end .try
    finally
    {
      IL_004a:  ldloc.2
      IL_004b:  brfalse.s  IL_0054

      IL_004d:  ldloc.2
      IL_004e:  callvirt   instance void ['mscorlib']'System'.'IDisposable'::'Dispose'()
      IL_0053:  nop
      IL_0054:  endfinally
      .line 27,27 : 13,32 ''
    }  // end handler
    IL_0055:  ldarg.0
    IL_0056:  ldarg.0
    IL_0057:  ldfld      class 'VCI_Comm_PlaybackNode.NodeConfig'.'CustomProperties' 'VCI_Comm_PlaybackNode'.'ConfigManager'::'_custProp'
    IL_005c:  call       instance void 'VCI_Comm_PlaybackNode'.'ConfigManager'::'set_Config'(class 'VCI_Comm_PlaybackNode.NodeConfig'.'CustomProperties')
    IL_0061:  nop
    .line 29,29 : 13,25 ''
    IL_0062:  ldc.i4.1
    IL_0063:  stloc.s    
    IL_0065:  br.s       IL_0067

    .line 30,30 : 9,10 ''
    IL_0067:  ldloc.s    
    IL_0069:  ret
  } // end of method 'ConfigManager'::'SetupConfig'

The source code of the function that fails looks like this:


    internal class ConfigManager
    {
        private CustomProperties _custProp;

        public bool SetupConfig(uint sessionID, string xmlConfig)
        {
            var key = sessionID.ToString();
            var serializer = new XmlSerializer(typeof(CustomProperties));

            using (var stream = new StringReader(xmlConfig))
            using (var reader = XmlReader.Create(stream))
            {
                _custProp = (CustomProperties) serializer.Deserialize(reader);
            }

            Config = _custProp;

            return true;
        }

        public CustomProperties Config { get; set; }
    }

The failing line is "return true;" if I read the output correctly.

Best Regards
Oscar

commented

Update:
Disabling .PDB generation for the project seem to solve the build error.

Unfortunately this is not an option I can use as I need the .pdb files.

Hi again Oscar,

This not from DllExport. It also reproduced and for me when Fody is installed even without DllExport.

You see this problem from DllExport because our library tried to compile already incorrect IL code.

Sample

Debug info: Full or pdb only:

namespace Sample1
{
    internal class ClassA
    {
        public bool m1()
        {
            int a, b, c;

            return true;
        }
    }
}

this works, but note the .locals def -->

  .method public hidebysig instance bool 
          'm1'() cil managed
  {
    // Code size       7 (0x7)
    .maxstack  1
    .locals init ([0] int32 'a',
             [1] int32 'b',
             [2] int32 'c',
             [3] bool )                                <<<<<<<
    .line 6,6 : 9,10 'D:\\tmp\\Sample1\\ClassA.cs'
    IL_0000:  nop
    .line 9,9 : 13,25 ''
    IL_0001:  ldc.i4.1
    IL_0002:  stloc.3                                  <<<<<<< ok
    IL_0003:  br.s       IL_0005

    .line 10,10 : 9,10 ''
    IL_0005:  ldloc.3                                  <<<<<<< ok
    IL_0006:  ret
  }
  • 0x0A - 0x0D i.e. stloc.0 - stloc.3 + see also 0xFE 0x0E
  • 0x06 - 0x09 i.e. ldloc.0 - ldloc.3 + see also 0xFE 0x0C

Now, when failed (by short forms - 0x13 and 0x11):

just define new var

int a, b, c, d; // >>> d 

because:

  • to reference on new variable (local variable via index from/to stack) now used 0x13 / 0x11 opcodes i.e. -> stloc.s / ldloc.s
  • and this is it, see below:
  .method public hidebysig instance bool 
          'm1'() cil managed
  {
    // Code size       9 (0x9)
    .maxstack  1
    .locals init ([0] int32 'a',
             [1] int32 'b',
             [2] int32 'c',
             [3] int32 'd',
             [4] bool )                                 <<<<<<
    .line 6,6 : 9,10 'D:\\tmp\\Sample1\\ClassA.cs'
    IL_0000:  nop
    .line 9,9 : 13,25 ''
    IL_0001:  ldc.i4.1
    IL_0002:  stloc.s                                   <<<<<< incorrect*
    IL_0004:  br.s       IL_0006

    .line 10,10 : 9,10 ''
    IL_0006:  ldloc.s                                   <<<<<< also here
    IL_0008:  ret
  }
  • 0x13 <unsigned int8> i.e. stloc.s index so yes, syntax error at token ':' in: IL_0004: br.s IL_0006

another interesting without debug info (as you already noticed) it generated correctly:

    .locals init (int32 V_0,
             int32 V_1,
             int32 V_2,
             int32 V_3,
             bool V_4)                  <<<<<
    IL_0000:  nop
    IL_0001:  ldc.i4.1
    IL_0002:  stloc.s    V_4            <<<<<
    IL_0004:  br.s       IL_0006

    IL_0006:  ldloc.s    V_4            <<<<<
    IL_0008:  ret
  }

Therefore, you need to report about this bug there https://github.com/Fody

commented

Thanks for your detailed analyze!

Fody/Fody#271 (comment)

I think we need to provide own ILDasm / ILAsm anyway (to try)
today it's also under the MIT License, so it cannot be big problem

probably v4.5.22220 works fine, but in general the ILDasm / ILAsm it's only wrapper (i.e. front-end to coreclr.dll and its dependencies ...)

TODO: to look

@OzzyL

temporarily, try with version 4.5.22220
you can compile it from here: https://github.com/dotnet/coreclr

I uploaded latest binaries here: 3F/coreclr#1
Later it will be as part of this package

ce2536e - should fix this problem

ilasm_0x13_0x11

via MSBuild Properties:

<DllExportOurILAsm>true</DllExportOurILAsm>
commented

I can confirm that ce2536e solves the issue.
Big thank you for your support!

@OzzyL

Everything looks super. I can build all my projects in Visual Studio 2015 now.

I recommend to wait public release, because I'm not sure about solution above for this problem:

3F/coreclr#2

maybe you know ? what's license for cvtres.exe (Windows Resource To Object Converter) ?

or free alternative to compile .res -> obj COFF-format (that will be placed in .rsrc section (PE)) ?
like windres, but it does not support our .res (probably need to convert .res -> .rc -> obj COFF :))

I released new version of coreclr for DllExport project:

# coreclr \ ILAsm

[v4.5.1]

    * FIXED: Fixed using of cvtres (.res -> obj COFF-format) in mscorpe.
             Possible crash: https://github.com/3F/coreclr/issues/2
             Related Issue: https://github.com/3F/DllExport/issues/17

    * NEW: Implemented additional searching of the converters of resources:
           Environment PATH, local directory, and other additional from user path.
           Now it also can be wrapped like ` mytool.cmd -> cvtres.exe %* ` etc.

    * NEW: Added new /CVRES (/CVR) key to ilasm.exe
           `/CVRES=<path_to_file>   Set path to cvtres tool: /CVR=cvtres.exe /CVR=tool\cvtres.cmd /CVR=D:\tool\`

    * NOTE: based on 4.5.22220.0  / coreclr 1.0.4
                     ^ ^  ^    ^
                     | |  |    |-- VER_FILEVERSIONREVISION
                     | |  |------- VER_FILEVERSIONBUILD
                     | |---------- VER_FILEVERSIONMINOR
                     |------------ VER_MAJORVERSION

and already updated logic for this issue (more correct now).

You can test this from - 5203d82

@3F any plans to merge back your changes to CoreCLR upstream or you plan to keep your own version?

@denfromufa probably yes, later. Because part of my changes should be useful even for main CoreCLR, but mainly it was specially for DllExport so I will look into later.

I've also plan to reconsider PE modifications at all, because ILAsm version on coreclr have a lot of limitations instead of full native version.
But as I know, MS shares only this version via coreclr only. Maybe today o_O

However ! old ILDasm v4.5.22220.0 initially does not contain this problem as it described above. And anyway, this changes should not affect on full version of ILDasm/ILAsm.

my new illustration of this problem here (please note, as I see, this is not related for DllExport project at all): Fody/Fody#271 (comment)

...
**1304** & **1104** are correct instructions ... 

    /* 0x000002A1 17           */ IL_0001: ldc.i4.1
    /* 0x000002A2 1304         */ IL_0002: stloc.s   4
    /* 0x000002A4 2B00         */ IL_0004: br.s      IL_0006

    /* 0x000002A6 1104         */ IL_0006: ldloc.s   4


full body: `133001000900000002000011 -> 001713042B0011042A`

    /* 0x00000495 17           */ IL_0001: ldc.i4.1
    /* 0x00000496 1304         */ IL_0002: stloc.s   V_4
    /* 0x00000498 2B00         */ IL_0004: br.s      IL_0006

    /* 0x0000049A 1104         */ IL_0006: ldloc.s   V_4

full body: `133001000900000003000011 -> 001713042B0011042A`

i.e. the main difference - .locals def
...

Unfortunately I have no access to source code of full version ILDasm so it's hard for my time to say what's going on, but in general, anyone else should look Fody project in this chain as I said before.

As I am right, that custom CoreCLR build required only at build time, but at runtime we can use genuine CoreCLR 2.0 ?

@dmitriyse,

We're using this only for PE-modification of final modules (.exe/.dll), i.e. as an post-processing of build through reassembling IL code.

Also the using of custom ILAsm\ILDAsm (on coreclr) should be only when option DllExportOurILAsm ("our IL Assembler") is activated.

  1. As I understand, even well-patched PE (.exe/.dll) cannot be used on Linux/Mac as .so library
  2. Does custom CoreCLR is able to post-process .NetCore 2.0 assemblies ?
  3. Did you try to use DllExport toolset with .Net Core 2.0 ?

1 & 2: It depends on coreclr implementation that should finally process the requests from unmanaged layer, read this: #45 (comment) - i.e. note again, clr environment is a core handler of this mechanism, while the final part of our modifications will be processed through mscorpe that will not to do anything except headers.

3: I have not yet considered coreclr for DllExport and have no plan to try support this at least in the next few months. It should be possible anyway, but seems not with current coreclr implementation.