1

Have a look at the following code:

static void Main(string[] args)
{
    string s = null;
    string[] myArray = new string[1];

    { } // do something evil here

    if (s.GetType() == typeof(int))
    {
        Console.WriteLine("This should not happen!"); 
    }
    Console.ReadLine();
}

Is there any way to get This should not happen to write? One would assume not. However, it can be done with the debugger: Put a breakpoint into the line { } // do something evil here and execute the following commands in the Immediate Window before continuing:

((object[])myArray)[0] = 99;
s = myArray[0];

Execution continues and This should not happen will be printed. Tested with Visual Studio 2008; here is a screenshot:

screenshot

Is this kind of trickery only possible with the debugger or is there some way to do such an "unsafe assignment" in code?

(Obviously, I ask only out of scientific curiosity. This question and the related comments made me ask this question.)

Community
  • 1
  • 1
Heinzi
  • 167,459
  • 57
  • 363
  • 519
  • 1
    I think it's one of these "who debugs the debugger" questions: I think you found a bug in the VS debugger. – Sergey Kalinichenko Jul 14 '13 at 17:23
  • Very interesting topic, but isn't this question just a duplicate of the question you link? – Jeppe Stig Nielsen Jul 14 '13 at 17:27
  • 1
    Being able to break the rules is rather the point of a debugger. You can arbitrarily change code execution order, freeze a thread, mutate a string, directly poke bytes in the GC heap, etc. Sure you can do this in code as well, pointers let you poke whatever you want. It just isn't very useful. – Hans Passant Jul 14 '13 at 20:15
  • First box an int and then use one of the reinterpret cast tricks. For example by creating a union using explicit layout. – CodesInChaos Jul 14 '13 at 20:44
  • @JeppeStigNielsen: It's the same topic but a different question (`Why does this happen?` vs. `Can this be done in code as well?`). – Heinzi Jul 14 '13 at 21:30
  • @HansPassant Can you also do an assignment like `someStringVariable = new object();` through the debugger? If not, why the difference between the type-safety of a "single" variable and that of an array entry? Would that be by design, or by "coincidence"? – Jeppe Stig Nielsen Jul 15 '13 at 17:12

1 Answers1

3

One technique is using LayoutKind.Explicit to implement a union which can be used to reinterpret cast an arbitrary object to string. First box an int, then assign it to the object field of the union and then read out the string field.

[StructLayout(LayoutKind.Explicit)]
public struct Evil
{
    [FieldOffset(0)]
    public string s;

    [FieldOffset(0)]
    public object o;
}

string ReinterpretCastToString(object o)
{
    Evil evil=new Evil();
    evil.o=o;
    return evil.s;
}

void Main()
{
    string s = ReinterpretCastToString(1);

    if (s.GetType() == typeof(int))
    {
        Console.WriteLine("This should not happen!"); 
    }
}

This is most likely undefined behavior that may stop working at any time. Obviously you shouldn't use this in a real program.

CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
  • I'm surprised that this even compiles, given that the size of the string cannot be known at compile time. – Robert Harvey Jul 14 '13 at 20:56
  • 1
    @RobertHarvey All references have the same size 4 or 8 bytes depending on the CPU architecture. This is essentially casting from one pointer type to another. – CodesInChaos Jul 14 '13 at 20:59
  • Oh crap, just noticed a third-part lib used in one of my projects actually uses this technique to cast between `int[]` and `float[]`. – CodesInChaos Jul 14 '13 at 21:04