C# compiler bug challenge!

A

Alun Harford

I've recently been playing with TypedReferences (basically type-safe
pointers).
You can't have a field of type TypedReference because it would make
garbage collection really hard (the garbage collector would need to work
out that you're holding on to a TypedReference to a variable within a
struct but not the struct itself).
For the same reason, you can't cast a TypedReference to an object.

So I wondered what would happen if I used one in a closure.

public class Program
{
public struct Foo
{
public int A { get; set; }
}
public static void Main(string[] args)
{
Foo foo = new Foo();
TypedReference tr = __makeref(foo.A);
Action a = () => Console.WriteLine( __refvalue(tr, int));
}
}

Bang! On VS2008 it crashes the compiler, and on VS2005 it crashes the
whole IDE. This shouldn't come as too much of a surprise: I can't think
of a way this could possibly be compiled into IL. I think all the
compiler could really do is to produce an error message instead of crashing.

It looks like the MS implementation of the CLR isn't quite compatible
with MS C#.

The .NET framework uses TypedReferences internally, so the challenge is:

Can you figure out a less clearly silly way of getting this bug to
appear? Ideally without explicitly using TypedReferences?

Alun Harford
 
J

Jon Skeet [C# MVP]

Can you figure out a less clearly silly way of getting this bug to
appear? Ideally without explicitly using TypedReferences?

What I've got certainly isn't less silly, but it's different... and it
doesn't contain the token "TypedReference". It does still use
__refvalue and __makeref though:

using System;
using System.Reflection;
using System.Collections.Generic;

public class Program
{
public struct Foo
{
public int A { get; set; }
}

public static void Main(string[] args)
{
}

public IEnumerable<int> Bang()
{
Foo foo = new Foo();
yield return __refvalue(__makeref(foo.A), int);
}
}

I think we're way into the realms of deep, dark magic at this point
though...
 
J

Jeroen Mostert

Jon said:
I think we're way into the realms of deep, dark magic at this point
though...

No, just in the realm of undocumented keywords. Trying to push these can
easily cause compiler crashes, since they're presumably not stress- or
regression-tested (or, dare I say it, tested at all). As long as it works
for the cases the MS guys needed them for, I don't think they particularly
care either.
 
A

Alun Harford

Jon said:
What I've got certainly isn't less silly, but it's different... and it
doesn't contain the token "TypedReference". It does still use
__refvalue and __makeref though:

Very nice.
(I should point out that I only used the TypedReference token to prevent
a linebreak).

I think we're way into the realms of deep, dark magic at this point
though...

It's the best kind.

I've had a bit more of a play and got the C# compiler to produce invalid
IL without complaining.
I've also managed to work __makeref and __refvalue out of the code:

public class Program
{
public static void Main(string[] args)
{
var tr = TypedReference.MakeTypedReference(null, null);
Action a = () => tr.Equals(null);
}
}

It's neater, but it's clearly using TypedReferences...

Alun Harford
 
J

Jon Skeet [C# MVP]

Jeroen Mostert said:
No, just in the realm of undocumented keywords. Trying to push these can
easily cause compiler crashes, since they're presumably not stress- or
regression-tested (or, dare I say it, tested at all). As long as it works
for the cases the MS guys needed them for, I don't think they particularly
care either.

Hmm... I'm not sure about that. I suspect they'd rather know. Alun,
have you raised a bug?
 
D

Dejan Stanic

IMHO, experiencing funny behaviour of the compiler/IDE when playing with
some internal implementations details (__makeref and such aren't even
mentioned in ECMA standard) can be hardly called a 'bug'.

LP,
Dejan
 
J

Jon Skeet [C# MVP]

Dejan Stanic said:
IMHO, experiencing funny behaviour of the compiler/IDE when playing with
some internal implementations details (__makeref and such aren't even
mentioned in ECMA standard) can be hardly called a 'bug'.

I don't know - I'd argue that any input which crashes the compiler
rather than getting it to emit error messages is a bug.
 
D

Dejan Stanic

Well, that's true :)

Seriously, if there's /unsafe switch required for compiling stuff that
potentially allows you to shoot yourself in the foot,
there's should also be /IPromiseNotToUseThisForProductionCode for nukes like
__makeref...

LP,
Dejan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top