DLL Export conflicts with Fody in Visual Studio 2015
OzzyL opened this issue · comments
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
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 also0xFE 0x0E
0x06 - 0x09
i.e.ldloc.0 - ldloc.3
+ see also0xFE 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
Thanks for your detailed analyze!
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
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
via MSBuild Properties:
<DllExportOurILAsm>true</DllExportOurILAsm>
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:
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 ?
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.
- As I understand, even well-patched PE (.exe/.dll) cannot be used on Linux/Mac as .so library
- Does custom CoreCLR is able to post-process .NetCore 2.0 assemblies ?
- 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.