Compiler Bug when using ?. resulting in a Bad Image that fails PEVerify

时间:2016-07-11 21:31:33

标签: c# visual-studio-2015 roslyn c#-6.0

I stumbled across something odd: I got a BadImageFormatException without knowing what image (assembly) it could possibly refer to.

I reduced the solution so that it consists only of a single project with no dependencies:

enter image description here

As you can see, it only uses System (and mscorlib), and of course I don't load assemblies at run time.

It compiles as AnyCpu with .NET 4.5.2, VS 2015 with C#6, although none of this should really matter.

I tried to make a sample with C#5, but once I replace all the "?." operators, it stops happening.

I have hosted the project so that people can try it themselves:

git clone -b crash-sample https://github.com/jtheisen/moldinium.git

I clean-built and tested it on 4 machines, all showing the same effect.

The stack trace of the crash is:

Ex.: System.BadImageFormatException: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
   at IronStone.Moldinium.LiveList.<>c__DisplayClass10_0`1.<Where>b__2(ListEvent`1 v)
   at IronStone.Moldinium.ActionObserver`1.OnNext(T value) in C:\Source\Repos\moldinium\ConsoleApplication1\Rx.cs:line 51
...snipped...

Running PEVerify on the output produces the following error:

[IL]: Error: [C:\Source\Repos\moldinium\ConsoleApplication1\bin\Debug\Bad.exe : IronStone.Moldinium.LiveList+<>c__DisplayClass10_0`1[TSource]::b__2][offset 0x0000013B] Unable to resolve token.

Removing all the ?. operators from the Select.cs file resolves the issue.

Using ILSpy I have isolated the problem to:

IronStone.Moldinium.LiveList.<>c__DisplayClass10_0`1.<Where>b__2

You can see the IL Dumps of the method (via ILSpy) in a gist here. The Bad IL is when using ?. the Good IL is C# 5.0 style.

This has been build with VS2015.3

CSC Version: Microsoft (R) Visual C# Compiler version 1.3.1.60616

1 个答案:

答案 0 :(得分:3)

我无法帮助你,因为它确实是一个错误。但是我可以把你带到发生错误的地方,它可以帮助你在几行代码中重现这个错误。

namespace ElvisBugInNullableGenericStructWithNestedTypeParameter
{
    struct MyGenericStruct<T> { }
    class Program
    {
        static void Main() { }

        void Test<T>()
        {
            Func<T, bool> func = (arg =>
                {
                    MyGenericStruct<T>? v1 = null;
                    return v1?.ToString() == null;
                });
        }
    }
}

如果我将MyGenericStruct<T>?替换为MyGenericStruct<int>?,它将有效。

问题是,出于某种原因,当我们在可空结构中使用外部T然后我们尝试使用Elvis运算符?时,类型是未知的(无法解析令牌)。

<强>更新 如果您想修复案例,则无需删除所有Elvis操作符,只需将其从Subscribe方法中的public static ILiveList<TSource> Where<TSource>(this ILiveList<TSource> source, Func<TSource, Boolean> predicate)操作中删除即可。