Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

like image 370
John Avatar asked Jul 11 '16 21:07

John


1 Answers

I can't help you because it's indeed a bug. But I can take you to the point where the bug occur and it may help you to reproduce the bug in a few lines of code.

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;
                });
        }
    }
}

If I will replace MyGenericStruct<T>? with MyGenericStruct<int>? it will work.

The problem is that, from some reason, when we use the outer T in nullable struct and then we try to use the Elvis operator ? the type is unknown (unable to resolve token).

Update If you want to fix your case, you don't need to remove all Elvis operator, just remove them from Subscribe action within public static ILiveList<TSource> Where<TSource>(this ILiveList<TSource> source, Func<TSource, Boolean> predicate) method.

like image 143
Dudi Keleti Avatar answered Nov 03 '22 13:11

Dudi Keleti