Danger zone: true, false or...

Akos Nagy
Nov 1, 2017

As an MCT I regularly teach courses of different levels. And I have to say, I love teaching — that's the most efficient way to learn :)
A participant at one of my advanced courses brought me this little 'problem' (of course, this is not a 'real' line-of-business problem, just something to hack with):

static bool GetBool()
{
  
}

static void Main(string[] args)
{
  bool b = GetBool();
  bool expectedValue = true;
  if (b == expectedValue)
      Console.WriteLine("True");
  else if (b == !expectedValue)
      Console.WriteLine("False");
  else
     Console.WriteLine("Other");
  Console.ReadLine();
}

And the problem: how to complete the GetBool() method so that the conditional statement prints 'Other'?

Is this possible at all? We have a bool, and bools can be true or false. We have true in the expected value, so the first branch of the conditional is evaluated if GetBool() returns true, and the second if GetBool() returns false. There is really no other value that can be returned — or is it?

Well, generally speaking, no there isn't. If you could, that would mean that you can break .NET. And what better way to break managed code than to go unmanaged? :) Here's the little piece of code that breaks booleans:

static bool GetBool()
{
  bool[] bool0 = new[] { true };
  byte[] byte0 = new byte[] { 2 };
  GCHandle handler = GCHandle.Alloc(bool0, GCHandleType.Pinned);
  var ptr = handler.AddrOfPinnedObject();
  Marshal.Copy(byte0, 0, ptr, 1);
  return bool0[0];
}

Booleans in .NET have a size of 1 byte, so technically, you can copy any one byte long value over their allocated memory. And that's exactly what this little piece of code does.

You tried it and it doesn't work?

If you were curious and tried it and it doesn't work for you, look at the code again. Did you use the local variable for the comparison, or just wrote something like this:

 if (b == true)
      Console.WriteLine("True");
  else if (b == false)
      Console.WriteLine("False");
  else
     Console.WriteLine("Other");

If you do it like this, you'll always go into the first branch (unless you copied 0 into the bool array with Marshal.Copy). And why is that? If you look at the disassembled version of this second conditional, you'll see something like this:

00007FFBE3944355  mov         rcx,qword ptr [rbp+78h]  
00007FFBE3944359  cmp         dword ptr [rcx+8],3  
00007FFBE394435D  ja          00007FFBE3944364  
00007FFBE394435F  call        00007FFC433CF000  
00007FFBE3944364  mov         rcx,qword ptr [rbp+78h]  
00007FFBE3944368  movzx       ecx,byte ptr [rcx+13h]  
00007FFBE394436C  mov         dword ptr [rbp+5Ch],ecx  
00007FFBE394436F  mov         ecx,dword ptr [rbp+5Ch]  
00007FFBE3944372  test        ecx,ecx  
00007FFBE3944374  je          00007FFBE394438B

Here you can see that the test statement work on ecx, and into ecx the value returned from the method call is moved. And what is returned from the method? A byte pattern that's equivalent to 2, which is not 0, so the conditional jumps into the first if branch. There is no comparison in this piece of code.

If you look at the original conditional:

00007FFBE3924355  mov         rcx,qword ptr [rbp+78h]  
00007FFBE3924359  cmp         dword ptr [rcx+8],3  
00007FFBE392435D  ja          00007FFBE3924364  
00007FFBE392435F  call        00007FFC433CF000  
00007FFBE3924364  mov         rcx,qword ptr [rbp+78h]  
00007FFBE3924368  movzx       ecx,byte ptr [rcx+13h]  
00007FFBE392436C  mov         eax,dword ptr [rbp+84h]  
00007FFBE3924372  cmp         ecx,eax  
00007FFBE3924374  sete        cl  
00007FFBE3924377  movzx       ecx,cl  
00007FFBE392437A  mov         dword ptr [rbp+5Ch],ecx  
00007FFBE392437D  mov         ecx,dword ptr [rbp+5Ch]  
00007FFBE3924380  test        ecx,ecx  
00007FFBE3924382  je          00007FFBE3924399

You can see that the values are actually compared using cmp, and that's moved into ecx, and then tested. The first version doesn't do any comparison at all. This makes sense, if you think about it; after all writing if ( b==true ) equals writing if( b ) . There is no need to load an extra value into an extra register, you can just test the value itself.

All credit goes to Csaba, who shared this little piece of code with me.

Akos Nagy
Posted in .NET C# Teaching