Thursday, October 11, 2012

Another VC compiler optimization bug:(

Last week, my leader had another annoying problem, a snippet like below is not working at all. The GetBool function will assign the 2nd argument “value” to true internally, while when returning, it is still false.

   1: IMyNameValues src;
   2:  
   3: ...
   4:  
   5: if (destField == nullptr)
   6: {
   7:     bool value;
   8:     System::String^ key = strConverter.Utf8ToString(srcField.Name);
   9:     mGuts->CheckCode(src.GetBool(srcField.Name, value));
  10:     dest->AddField(key, value);
  11: }
  12: else if (destField->Type->DotNetType->Equals(System::Boolean::typeid))
  13: {
  14:     bool value;
  15:     const char* pName = srcField.Name;
  16:     mGuts->CheckCode((long)src.GetBool(srcField.Name, value));
  17:     dest->AddField(destField, value);
  18: }
  19:  
  20: ...
  21:  
  22: //the GetBool function's signature is like:
  23: long GetBool(const string& name, bool& value);

After debugging the codes, and found an interesting thing, the “&value” before entering the GetBool function is different from the one inside the function. Then, reading the disassembly code, and manually calculating the local variable address on the call stack (ebp + xxxx), it is really different from the actual address of the local variable.


Then, if I changed the name of the local variable “value”, making different for the if/else branches, and it works!



   1: if (destField == nullptr)
   2: {
   3:     bool value;
   4:     System::String^ key = strConverter.Utf8ToString(srcField.Name);
   5:     mGuts->CheckCode(src.GetBool(srcField.Name, value));
   6:     dest->AddField(key, value);
   7: }
   8: else if (destField->Type->DotNetType->Equals(System::Boolean::typeid))
   9: {
  10:     bool value1;
  11:     const char* pName = srcField.Name;
  12:     mGuts->CheckCode((long)src.GetBool(srcField.Name, value1));
  13:     dest->AddField(destField, value1);
  14: }

And if disabling compiler optimization, also fine. It seems to be a compiler optimization bug, And I tried to reproduce it with some sample small snippet, could not reproduce. Since the product codes are kind of over-designed, introducing too many unnecessary concepts, for instance, virtual inheritance, RTTI, CLI, and etc, also involving a bunch of mangled classes. I had no time to trim them to get a simple case.


Another simple solution is move the inner local variable forward, it also works, e.g.:



   1: bool value;
   2: if (destField == nullptr)
   3: {
   4:     System::String^ key = strConverter.Utf8ToString(srcField.Name);
   5:     mGuts->CheckCode(src.GetBool(srcField.Name, value));
   6:     dest->AddField(key, value);
   7: }
   8: else if (destField->Type->DotNetType->Equals(System::Boolean::typeid))
   9: {
  10:     const char* pName = srcField.Name;
  11:     mGuts->CheckCode((long)src.GetBool(srcField.Name, value));
  12:     dest->AddField(destField, value);
  13: }

No comments:

Post a Comment