lsmgms
asked on
Visual C++ bug?
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());
}
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());
}
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
BTW, disregart "and an operator issue" |o)
ASKER
Hi pjknibbs,
Actually I have compiled both of the program under release conf. The only difference is the /Od and /O2.
Actually I have compiled both of the program under release conf. The only difference is the /Od and /O2.
ASKER
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.
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.
ASKER
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.
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.
>>I think /Od is correct and /O2 is the one making mistake.
Well, then you might want to try
return ++gChanNum;
:o)
Well, then you might want to try
return ++gChanNum;
:o)
ASKER
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
Thanks
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).
ASKER
Thanks for help from all of you.
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.