Danger zone: true, false or...
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.