I've been working on a lot of C#/.Net code recently, and noticed something (potentially) strange.
The team I'm in is developing using Windows 7 Professional and Visual Studio 2008 (for what it's worth), and when some of the code produced is run on different versions of windows (in my example, Windows XP Professional with .Net 3.5 installed) we get some slightly strange behaviour.
What I've noticed is a very specific set of nested ifs (that each call the same method, but with different parameters), within a switch block seems to be behaving differently at run-time on one specific machine than it is on the development machines. An example of what I mean is this:
switch (someVariable)
{
case true:
//do some stuff
//this case seems fine when stepped through
break;
case false:
//do some stuff
//this is the case that causes problems
if (Foo())
{
if(Bar())
{
someOtherMethod();
//I'll call these the nested ifs
if (object.SomeValue == targetValueOne)
FooBar(string, someParam, int anotherParam);
if (object.SomeValue == targetValueTwo)
FooBar(string differentStrParam, int differentIntParam);
else
FooBar(string thirdStrParam, int thirdIntParam);
}
}
else
{
//do some different things
}
break;
}
The example is overly complicated, but it still holds (pretty much) true to the code I have in front of me (there are extra if's to check object.SomeValue's value).
On the Windows 7 (development) machines, the code runs perfectly - I've stepped through it with each permutation of object.SomeValue and each code path is executed as planned. However, when this code is run on a Windows XP (belonging to a tester) machine, the nested ifs don't seem to even get called, especially when Bar() returns true.
There are two versions of FooBar(), one that returns and one that doesn't. I'm explicitly calling the version that doesn't, here.
Foo() and Bar() are two different set-up methods, if they complete the set-up steps then they return true, otherwise they return false.
As I've said above, When this code is run on the tester's machine, the nested ifs are skipped entirely. Whereas they are evaluated correctly on the development machines. I know that the JIT compiles to native code at run time, and that native code is specific for the machine that it's running on.
So, I guess I'm asking if anyone knows whether it could be the JIT on the tester's machine is what's causing these nested ifs to be skipped, or whether I've missed something out? Or could the JIT compiler be trying to optimise this block and producing code that doesn't actually perform the way it's supposed to?
Maybe a clearer example:
switch (Hawrdware.SomeProperty)
{
case true:
//do some stuff
//this case seems fine when stepped through
break;
case false:
//do some stuff
//this is the case that causes problems
if (SetupHardware()) //calls our library functions
{ //these have been tested thoroughly
if(WaitForCorrectResponse()) //waits for the correct post-setup
{ //message from the hardware
SendOTAMessageFromHardware(string message);
//I'll call these the nested ifs
if (Hawrdware.PropertyOne == targetValueOne)
SendOTAMessageFromHardware(string message, int timeOutForResponse);
if (Hawrdware.PropertyTwo == targetValueTwo)
SendOTAMessageFromHardware(string message, int timeOutForResponse);
else
SendOTAMessageFromHardware(string message, int timeOutResposnse);
}
}
else
{
//do some different things
}
break;
}
public void SendOTAMessage(string message)
{
if (message != null)
{
device.Write(message);
//Hardware's on-board OS takes care of the rest
}
}
public void SendOTAMessage(string message, int TimeOut)
{
if (message != null)
{
StopWatch clock = new StopWatch();
device.Write(message);
//Hardware's on-board OS takes care of the rest
while (time.Elapsed.TotalSeconds < TimeOut)
{
//wait and see if we get a response
//if we do, store it in a string (legacy
//reasons state we have to do this
}
}
}
public string SendOTAMessage(string message, int TimeOut)
{
if (message != null)
{
StopWatch clock = new StopWatch();
device.Write(message);
//Hardware's on-board OS takes care of the rest
while (time.Elapsed.TotalSeconds < TimeOut)
{
//wait and see if we get a response
//if we do, return this message as a string
}
}
}
You need to rule out every other possible factor, unless you've got something more conclusive than "My if statement never gets hit in the debugger".
Build two identical machines:
Throughout this testing, ensure that for EVERY action you perform on one, you perform identically on the other.
If you really suspect faulty compilation do the following:
If you see Hardware.SomeProperty==false + trace inside case statement but no trace inside the methods it might be right. No need to step through either, removing the debugger from the equation will only make things simpler.