Compiler generated incorrect code for anonymous methods [MS BUG FIXED]
Asked Answered
A

2

30

See the following code:

public abstract class Base
{
    public virtual void Foo<T>() where T : class
    {
        Console.WriteLine("base");
    }
}

public class Derived : Base
{
    public override void Foo<T>()
    {
        Console.WriteLine("derived");
    }

    public void Bang()
    {
        Action bang = new Action(delegate { base.Foo<string>(); });
        bang();    //VerificationException is thrown
    }
}

new Derived().Bang(); throws an exception. Inside the generated CIL of the method Bang I got:

call instance void ConsoleApp.Derived::'<>n__FabricatedMethod1'<string>()

and the signature of the compiler generated method:

method private hidebysig 
    instance void '<>n__FabricatedMethod1'<T> () cil managed 
{
    .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
        01 00 00 00
    )       
    .maxstack 8

    IL_0000: ldarg.0
    IL_0001: call instance void ConsoleApp.Base::Foo<!!T>()
    IL_0006: ret
}

I think the correct code should be '<>n__FabricatedMethod1'<class T>. Is it a bug? By the way, without using delegate{ }(lambda expression is the same), the code works fine with syntax sugars.

Action good = new Action(base.Foo<string>());
good();  //fine

EDIT I'm using VS2012 RTMRel in windows8 RTM, .net framework 4.5

EDIT This bug is now fixed.

Agnew answered 10/10, 2012 at 6:49 Comment(15)
Your code works for me. Which version of C#/.Net/Visual Studio are you using? Which platform are you targeting?Cuckooflower
@jeroenh: C# 4.5 VS2012.Agnew
I tried with VS2010, C# 4 and 3.5. Don't have access to 2012 right now but will certainly try it tonight.Cuckooflower
Confirmed on VS2012. Gets a 'type argument 'T' violates the constraint of type parameter 'T'.' which is interesting.Firebug
Output from PEVerify indicates the compiler has indeed a bug... [IL]: Error: [ConsoleApplication3.exe : ConsoleApplication3.Derived::<>n__FabricatedMethod1[T]][ offset 0x00000001] Unable to resolve token. 1 Error(s) Verifying ConsoleApplication3.exeFirebug
@leppie: LOL I'm just doing the same thing.Agnew
I think, based on the comments so far, you can fairly safely say you've found a bug, and answer your own question with that. The only way in which this could be anything other than a compiler bug is if the language specification doesn't allow base method calls in delegates (I haven't checked), but even then, the lack of a proper diagnostic is a missing desirable feature in the compiler. (Do report it to Microsoft, of course.)Robinia
BTW, if you remove the where T : class constraint from the virtual method. The code verifies, and runs correctly.Firebug
where T : struct also fails, but where T : IComparable or where T : Base works. Edit: where T : new() also fails.Firebug
@leppie: Reported to MS, ticket number: 766845Agnew
@DannyChen: :) I added a link back to here for reference.Firebug
This seems similar to #5291059, although that caused BadImageFormatException and MS claims it has been fixed.Chops
I find this strange. Isn't the delegate there whether you explicitly use the delegate keyword or not? I thought the two syntaxes were equivalent and am therefore surprised they could lead to different IL unless the actual parsing had a bug with more far-reaching consequences.Timmy
@TheDag Doesn't the delegate { } syntax create an extra anonymous method that then calls Foo, where as new Action(base.Foo<string>) calls Foo directly without the extra indirection?Pizarro
Why do you feel the need to plaster the link and the fixed status all over the question?Plait
A
3

It is confirmed as a bug and now fixed

Update: the Connect article no longer exists. The bug is fixed.

Agnew answered 14/12, 2012 at 7:52 Comment(1)
Pity we will never know when this will reach us. Microsoft should really communicate better on that site...Firebug
S
1

At first - This is a possible way how to fix this, but probably not an answer to your question. (But comments don´t have code formating)

I believe this is similar to this: Outer Variable Trap, because you are using Foo() method as a variable and there is a bug (or maybe a feature) in .NET

I have tried to change Bang() method to this

public void Bang()
{
    Action baseMethod = base.Foo<string>;
    Action bang = new Action(delegate { baseMethod(); });
    bang();    //VerificationException is thrown
}

And it works and the result is "base"

I hope it helps a little bit.

Severity answered 17/10, 2012 at 10:4 Comment(1)
FYI, Comments do have code formatting, you just can't include line breaks and are still limited by the total number of characters (which includes markdown)Decency

© 2022 - 2024 — McMap. All rights reserved.