Solved

Visual C++ bug?

Posted on 2002-06-14
10
313 Views
Last Modified: 2008-03-10
Hi,

I encounter a funny problem.  If I compile and run the following exe, there will be different output in release(wrong output) and debug(correct output):

Release: compiler option: /O2
Output>> C: a val = 1

Debug: compiler option: /Od
Output>> C: a val = 0

It looks like the optimization option /O2 and /Od causing the problem.  However, it only occurred under the __try/__catch{} clause.  If I remove it, it is OK.  Also, if I move to .cpp and using try{} and catch(), it is also OK.  Another way is chaged to something like this:

//return gChanNum++;

  int ret = gChanNum++;
  return ret;

It also works.  I have increase warning level to 4 but no warning.  Any idea?  I wonder whether it is a MSVC bug or not.


// main.c
#include <stdio.h>

int gChanNum = 0;

int get_next_num()
{
     __try{

          return gChanNum++;

     }

     __except( printf("except")){

          return -1;
     }
}

/*

   /Od
   C: a val = 0

  /O2 (maximize speed: release config )
   C: a val = 1

  */

void main(void)
{
     printf("\n C: a val = %d", get_next_num());
}


0
Comment
Question by:lsmgms
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 3
  • 2
10 Comments
 
LVL 12

Expert Comment

by:pjknibbs
ID: 7078143
This could well be an optimisation issue. Compiler optimisations are pretty good, on the whole, but they can't cover every possible piece of code which is likely to be passed to them, and sometimes they make mistakes which cause the code to work in an incorrect fashion. Out of interest, what happens if you compile this code as a release link with optimisations turned OFF?

Bear in mind you can set the optimisation level individually for every file in your project, so you could easily turn off the faulty optimisation on just this one file and keep the rest the same.
0
 
LVL 86

Accepted Solution

by:
jkr earned 200 total points
ID: 7078207
It both an optimization and an operator issue - try to disassemble the binary that you get for both /Od and /O2 and compare the relevant parts:

/Od

  00401028: C7 45 FC 00 00 00  mov         dword ptr [ebp-4],0
            00
  0040102F: A1 E8 98 40 00     mov         eax,[004098E8]
  00401034: 8B 0D E8 98 40 00  mov         ecx,dword ptr ds:[004098E8h]
  0040103A: 83 C1 01           add         ecx,1
  0040103D: 89 0D E8 98 40 00  mov         dword ptr ds:[004098E8h],ecx
  00401043: 89 45 E4           mov         dword ptr [ebp-1Ch],eax
  00401046: C7 45 FC FF FF FF  mov         dword ptr [ebp-4],0FFFFFFFFh
            FF
  0040104D: 8B 45 E4           mov         eax,dword ptr [ebp-1Ch]
  00401050: EB 22              jmp         00401074
  00401052: 68 30 70 40 00     push        407030h
  00401057: E8 41 00 00 00     call        0040109D
  0040105C: 83 C4 04           add         esp,4
  0040105F: C3                 ret

/O2

  00401028: C7 45 FC 00 00 00  mov         dword ptr [ebp-4],0
            00
  0040102F: A1 E8 98 40 00     mov         eax,[004098E8]
  00401034: 40                 inc         eax
  00401035: A3 E8 98 40 00     mov         [004098E8],eax
  0040103A: C7 45 FC FF FF FF  mov         dword ptr [ebp-4],0FFFFFFFFh
            FF
  00401041: 8B 4D F0           mov         ecx,dword ptr [ebp-10h]
  00401044: 64 89 0D 00 00 00  mov         dword ptr fs:[00000000h],ecx
            00
  0040104B: 5F                 pop         edi
  0040104C: 5E                 pop         esi
  0040104D: 5B                 pop         ebx
  0040104E: 8B E5              mov         esp,ebp
  00401050: 5D                 pop         ebp
  00401051: C3                 ret
  00401052: 68 30 70 40 00     push        407030h
  00401057: E8 44 00 00 00     call        004010A0
  0040105C: 83 C4 04           add         esp,4
  0040105F: C3                 ret

In the /Od case, you have

  00401034: 8B 0D E8 98 40 00  mov         ecx,dword ptr ds:[004098E8h]
  0040103A: 83 C1 01           add         ecx,1
  0040103D: 89 0D E8 98 40 00  mov         dword ptr ds:[004098E8h],ecx

whereas in the /O2 case, it is

  0040102F: A1 E8 98 40 00     mov         eax,[004098E8]
  00401034: 40                 inc         eax
  00401035: A3 E8 98 40 00     mov         [004098E8],eax

As function calls usually sotr the return value in EAX, everything is fine with /O2, whereas /Od seems to store the value in the wrong register and stores the content of a local variable in EAX (mov eax,dword ptr [ebp-1Ch]) - why it does it and what automatic variable that is remains unclear to me

(BTW, I am not an ASM guru, so I am not sure if this is a 'perfect' answer).
0
 
LVL 86

Expert Comment

by:jkr
ID: 7078211
BTW, disregart "and an operator issue" |o)
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 1

Author Comment

by:lsmgms
ID: 7079907
Hi pjknibbs,

Actually I have compiled both of the program under release conf.  The only difference is the /Od and /O2.
0
 
LVL 1

Author Comment

by:lsmgms
ID: 7079913
Hi jkr,

Thanks for your binary analysis.  It gives me more clues now.

>>everything is fine with /O2, whereas /Od seems
to store the value in the wrong register and stores the content of a local variable in EAX

I think /Od is correct and /O2 is the one making mistake.

In the /Od case:
0040102F: A1 E8 98 40 00     mov         eax,[004098E8]
 00401034: 8B 0D E8 98 40 00  mov         ecx,dword ptr ds:[004098E8h]
 0040103A: 83 C1 01           add         ecx,1
 0040103D: 89 0D E8 98 40 00  mov         dword ptr ds:[004098E8h],ecx
 00401043: 89 45 E4           mov         dword ptr [ebp-1Ch],eax

The gChanNum is fetch to eax and ecx.  However, only ecx and finally gChanNum will increase by 1.  The eax still keep the initial value during fetch.

While in the /O2 case:
0040102F: A1 E8 98 40 00     mov         eax,[004098E8]
 00401034: 40                 inc         eax
 00401035: A3 E8 98 40 00     mov         [004098E8],eax

There is no ecx to work for increment and eax itself will get increase by one.

0
 
LVL 1

Author Comment

by:lsmgms
ID: 7079918
Hi,

Another interesting try: remove the __try/__except clause:


; 9    :      /*__try*/{
; 10   :
; 11   :           return gChanNum++;

  00000     8b 0d 00 00 00
     00           mov      ecx, DWORD PTR _gChanNum
  00006     8b c1           mov      eax, ecx
  00008     41           inc      ecx
  00009     89 0d 00 00 00
     00           mov      DWORD PTR _gChanNum, ecx

; 12   :
; 13   :      }
; 14   :
; 15   :      /*__except( printf("except")){
; 16   :
; 17   :           return -1;
; 18   :      }*/
; 19   : }


Again, ecx will be the working register while eax will store the initial value.
0
 
LVL 86

Expert Comment

by:jkr
ID: 7079919
>>I think /Od is correct and /O2 is the one making mistake.

Well, then you might want to try

         return ++gChanNum;

:o)
0
 
LVL 1

Author Comment

by:lsmgms
ID: 7079922
Does anyone know any documentation about this?  Can I consider this is a MSVC bug?  Will it happen to other compiler like CBuilder or gcc?

Thanks
0
 
LVL 12

Expert Comment

by:pjknibbs
ID: 7082035
You won't find any documentation on optimisation bugs, and the chances are this WON'T happen on any other compiler--however, there'll be another problem they suffer from at some other stage in your code, so you're probably better off sticking with the existing compiler since at least you have a fix (e.g. compile with a different set of optimisations turned on).
0
 
LVL 1

Author Comment

by:lsmgms
ID: 7082741
Thanks for help from all of you.
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In days of old, returning something by value from a function in C++ was necessarily avoided because it would, invariably, involve one or even two copies of the object being created and potentially costly calls to a copy-constructor and destructor. A…
C++ Properties One feature missing from standard C++ that you will find in many other Object Oriented Programming languages is something called a Property (http://www.experts-exchange.com/Programming/Languages/CPP/A_3912-Object-Properties-in-C.ht…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…

696 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question