In release mode, code behavior is not as expected

C++COptimizationVisual Studio-2008Compiler Bug

C++ Problem Overview


The following code generates different results under debug mode and release mode (using Visual Studio 2008):

int _tmain(int argc, _TCHAR* argv[])
{

    for( int i = 0; i < 17; i++ ) 
    { 
        int result = i * 16;

        if( result > 255 )
        {
            result = 255;
        }

        printf("i:%2d, result = %3d\n", i, result) ; 
    } 

    return 0;
}

The output of debug mode, which is as expected:

i: 0, result =   0
i: 1, result =  16
(...)
i:14, result = 224
i:15, result = 240
i:16, result = 255

The output of release mode, where i:15 result is not correct:

i: 0, result =   0
i: 1, result =  16
(...)
i:14, result = 224
i:15, result = 255
i:16, result = 255

By choosing "Optimization -> Not to optimize" in Visual Studio under release mode, the output result will be correct. However I would like to know why the optimization process could lead to erroneous output.


Update:

As suggested by Mohit JainBy, prints by:

printf("i:%2d, result = %3d, i*16=%d\n", i, result, i*16) ;

The release mode output is correct:

i: 0, result =   0, i*16=0
i: 1, result =  16, i*16=16
(...)
i:14, result = 224, i*16=224
i:15, result = 240, i*16=240
i:16, result = 255, i*16=256

C++ Solutions


Solution 1 - C++

This is interesting, at least from a historical perspective. I can reproduce the problem with VC 2008 (15.00.30729.01) and VC 2010 (16.00.40219.01) (targeting either 32-bit x86 or 64-bit x64). The problem doesn't occur with any of the compilers I have tried starting with VC 2012 (17.00.61030).

The command I used to compile: cl /Ox vc15-bug.cpp /FAsc

Since VC 2008 (and 2010) is rather old and the fix has been in for several years now, I don't think you can expect any action from Microsoft except to use a newer compiler (though maybe someone can suggest a workaround).

The problem is that the test to determine if the value should be forced to 255 is done based on the loop count rather than the actual result of the i * 16 expression. And the compiler simply gets the count wrong for when it should start forcing the value to 255. I have no idea why that happens - it's just the effect that I see:

; 6    : 	for( int i = 0; i < 17; i++ ) 

  00001	33 f6		 xor	 esi, esi
$LL4@main:
  00003	8b c6		 mov	 eax, esi
  00005	c1 e0 04	 shl	 eax, 4

; 7    : 	{ 
; 8    : 		int result = i * 16;
; 9    : 
; 10   : 		if( result > 255 )

  // the value `esi` is compared with in the following line should be 15!
  00008	83 fe 0e	 cmp	 esi, 14			; 0000000eH
  0000b	7e 05		 jle	 SHORT $LN1@main

; 11   : 		{
; 12   : 			result = 255;

  0000d	b8 ff 00 00 00	 mov	 eax, 255		; 000000ffH
$LN1@main:

; 13   : 		}

Update: All versions of VC I have installed earlier than VC 2008 have the same bug, except VC6 - compiling the program crashes the VC6 compiler:

vc15-bug.cpp(10) : fatal error C1001: INTERNAL COMPILER ERROR

So this is a bug that lasted in MSVC in one form or another for more than 10 years!

Solution 2 - C++

Assuming your reported facts are correct, this would be a compiler bug. Check the latest version of the compiler. If the bug is still present, submit a bug report.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLorris LinView Question on Stackoverflow
Solution 1 - C++Michael BurrView Answer on Stackoverflow
Solution 2 - C++David HeffernanView Answer on Stackoverflow